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();
348 // #i97146# check if that view is still available
349 // else probably the idle format timer fired while we're already
351 EditView
* pView
= aIdleFormatter
.GetView();
352 for( sal_uInt16 nView
= 0; nView
< aEditViews
.Count(); nView
++ )
354 if( aEditViews
[nView
] == pView
)
356 FormatAndUpdate( pView
);
362 IMPL_LINK_INLINE_END( ImpEditEngine
, IdleFormatHdl
, Timer
*, EMPTYARG
)
364 void ImpEditEngine::CheckIdleFormatter()
366 aIdleFormatter
.ForceTimeout();
367 // Falls kein Idle, aber trotzdem nicht formatiert:
368 if ( !IsFormatted() )
372 void ImpEditEngine::FormatFullDoc()
374 for ( sal_uInt16 nPortion
= 0; nPortion
< GetParaPortions().Count(); nPortion
++ )
375 GetParaPortions()[nPortion
]->MarkSelectionInvalid( 0, GetParaPortions()[nPortion
]->GetNode()->Len() );
379 void ImpEditEngine::FormatDoc()
381 if ( !GetUpdateMode() || IsFormatting() )
384 EnterBlockNotifications();
386 bIsFormatting
= sal_True
;
388 // Dann kann ich auch den Spell-Timer starten...
389 if ( GetStatus().DoOnlineSpelling() )
390 StartOnlineSpellTimer();
393 sal_Bool bGrow
= sal_False
;
395 Font
aOldFont( GetRefDevice()->GetFont() );
397 // Hier schon, damit nicht jedesmal in CreateLines...
398 sal_Bool bMapChanged
= ImpCheckRefMapMode();
400 aInvalidRec
= Rectangle(); // leermachen
401 for ( sal_uInt16 nPara
= 0; nPara
< GetParaPortions().Count(); nPara
++ )
403 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
404 if ( pParaPortion
->MustRepaint() || ( pParaPortion
->IsInvalid() && pParaPortion
->IsVisible() ) )
406 if ( pParaPortion
->IsInvalid() )
408 sal_Bool bChangedByDerivedClass
= GetEditEnginePtr()->FormattingParagraph( nPara
);
409 if ( bChangedByDerivedClass
)
411 pParaPortion
->GetTextPortions().Reset();
412 pParaPortion
->MarkSelectionInvalid( 0, pParaPortion
->GetNode()->Len() );
415 // bei MustRepaint() sollte keine Formatierung noetig sein!
416 // 23.1.95: Evtl. ist sie durch eine andere Aktion aber doch
417 // ungueltig geworden!
418 // if ( pParaPortion->MustRepaint() || CreateLines( nPara ) )
419 if ( ( pParaPortion
->MustRepaint() && !pParaPortion
->IsInvalid() )
420 || CreateLines( nPara
, nY
) )
422 if ( !bGrow
&& GetTextRanger() )
424 // Bei einer Aenderung der Hoehe muss alles weiter unten
425 // neu formatiert werden...
426 for ( sal_uInt16 n
= nPara
+1; n
< GetParaPortions().Count(); n
++ )
428 ParaPortion
* pPP
= GetParaPortions().GetObject( n
);
429 pPP
->MarkSelectionInvalid( 0, pPP
->GetNode()->Len() );
430 pPP
->GetLines().Reset();
434 if ( IsCallParaInsertedOrDeleted() )
435 GetEditEnginePtr()->ParagraphHeightChanged( nPara
);
436 pParaPortion
->SetMustRepaint( sal_False
);
439 // InvalidRec nur einmal setzen...
440 if ( aInvalidRec
.IsEmpty() )
442 // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()...
443 long nWidth
= Max( (long)1, ( !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height() ) );
444 Range
aInvRange( GetInvalidYOffsets( pParaPortion
) );
445 aInvalidRec
= Rectangle( Point( 0, nY
+aInvRange
.Min() ),
446 Size( nWidth
, aInvRange
.Len() ) );
450 aInvalidRec
.Bottom() = nY
+ pParaPortion
->GetHeight();
455 aInvalidRec
.Bottom() = nY
+ pParaPortion
->GetHeight();
457 nY
+= pParaPortion
->GetHeight();
460 // Man kann auch durch UpdateMode An=>AUS=>AN in die Formatierung gelangen...
461 // Optimierung erst nach Vobis-Auslieferung aktivieren...
462 // if ( !aInvalidRec.IsEmpty() )
464 sal_uInt32 nNewHeight
= CalcTextHeight();
465 long nDiff
= nNewHeight
- nCurTextHeight
;
467 aStatus
.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTHEIGHTCHANGED
: EE_STAT_TEXTWIDTHCHANGED
;
468 if ( nNewHeight
< nCurTextHeight
)
470 aInvalidRec
.Bottom() = (long)Max( nNewHeight
, nCurTextHeight
);
471 if ( aInvalidRec
.IsEmpty() )
473 aInvalidRec
.Top() = 0;
474 // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt.
475 aInvalidRec
.Left() = 0;
476 aInvalidRec
.Right() = !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height();
480 nCurTextHeight
= nNewHeight
;
482 if ( aStatus
.AutoPageSize() )
486 for ( sal_uInt16 nView
= 0; nView
< aEditViews
.Count(); nView
++ )
488 EditView
* pView
= aEditViews
[nView
];
489 ImpEditView
* pImpView
= pView
->pImpEditView
;
490 if ( pImpView
->DoAutoHeight() )
492 Size
aSz( pImpView
->GetOutputArea().GetWidth(), nCurTextHeight
);
493 if ( aSz
.Height() > aMaxAutoPaperSize
.Height() )
494 aSz
.Height() = aMaxAutoPaperSize
.Height();
495 else if ( aSz
.Height() < aMinAutoPaperSize
.Height() )
496 aSz
.Height() = aMinAutoPaperSize
.Height();
497 pImpView
->ResetOutputArea( Rectangle(
498 pImpView
->GetOutputArea().TopLeft(), aSz
) );
504 if ( aStatus
.DoRestoreFont() )
505 GetRefDevice()->SetFont( aOldFont
);
506 bIsFormatting
= sal_False
;
507 bFormatted
= sal_True
;
510 GetRefDevice()->Pop();
512 CallStatusHdl(); // Falls Modified...
514 LeaveBlockNotifications();
517 sal_Bool
ImpEditEngine::ImpCheckRefMapMode()
519 sal_Bool bChange
= sal_False
;
521 if ( aStatus
.DoFormat100() )
523 MapMode
aMapMode( GetRefDevice()->GetMapMode() );
524 if ( aMapMode
.GetScaleX().GetNumerator() != aMapMode
.GetScaleX().GetDenominator() )
526 else if ( aMapMode
.GetScaleY().GetNumerator() != aMapMode
.GetScaleY().GetDenominator() )
531 Fraction
Scale1( 1, 1 );
532 aMapMode
.SetScaleX( Scale1
);
533 aMapMode
.SetScaleY( Scale1
);
534 GetRefDevice()->Push();
535 GetRefDevice()->SetMapMode( aMapMode
);
542 void ImpEditEngine::CheckAutoPageSize()
544 Size
aPrevPaperSize( GetPaperSize() );
545 if ( GetStatus().AutoPageWidth() )
546 aPaperSize
.Width() = (long) !IsVertical() ? CalcTextWidth( TRUE
) : GetTextHeight();
547 if ( GetStatus().AutoPageHeight() )
548 aPaperSize
.Height() = (long) !IsVertical() ? GetTextHeight() : CalcTextWidth( TRUE
);
550 SetValidPaperSize( aPaperSize
); //Min, Max beruecksichtigen
552 if ( aPaperSize
!= aPrevPaperSize
)
554 if ( ( !IsVertical() && ( aPaperSize
.Width() != aPrevPaperSize
.Width() ) )
555 || ( IsVertical() && ( aPaperSize
.Height() != aPrevPaperSize
.Height() ) ) )
557 // Falls davor zentriert/rechts oder Tabs...
558 aStatus
.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTWIDTHCHANGED
: EE_STAT_TEXTHEIGHTCHANGED
;
559 for ( sal_uInt16 nPara
= 0; nPara
< GetParaPortions().Count(); nPara
++ )
561 // Es brauchen nur Absaetze neu formatiert werden,
562 // die nicht linksbuendig sind.
563 // Die Hoehe kann sich hier nicht mehr aendern.
564 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
565 ContentNode
* pNode
= pParaPortion
->GetNode();
566 SvxAdjust eJustification
= GetJustification( nPara
);
567 if ( eJustification
!= SVX_ADJUST_LEFT
)
569 pParaPortion
->MarkSelectionInvalid( 0, pNode
->Len() );
570 CreateLines( nPara
, 0 ); // 0: Bei AutoPageSize kein TextRange!
575 Size aInvSize
= aPaperSize
;
576 if ( aPaperSize
.Width() < aPrevPaperSize
.Width() )
577 aInvSize
.Width() = aPrevPaperSize
.Width();
578 if ( aPaperSize
.Height() < aPrevPaperSize
.Height() )
579 aInvSize
.Height() = aPrevPaperSize
.Height();
581 Size
aSz( aInvSize
);
584 aSz
.Width() = aInvSize
.Height();
585 aSz
.Height() = aInvSize
.Width();
587 aInvalidRec
= Rectangle( Point(), aSz
);
590 for ( sal_uInt16 nView
= 0; nView
< aEditViews
.Count(); nView
++ )
592 EditView
* pView
= aEditViews
[nView
];
593 pView
->pImpEditView
->RecalcOutputArea();
598 static sal_Int32
ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight
)
600 return ( nFontHeight
* 12 ) / 10; // + 20%
603 sal_Bool
ImpEditEngine::CreateLines( USHORT nPara
, sal_uInt32 nStartPosY
)
605 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
607 // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False
608 DBG_ASSERT( pParaPortion
->GetNode(), "Portion ohne Node in CreateLines" );
609 DBG_ASSERT( pParaPortion
->IsVisible(), "Unsichtbare Absaetze nicht formatieren!" );
610 DBG_ASSERT( pParaPortion
->IsInvalid(), "CreateLines: Portion nicht invalid!" );
612 BOOL bProcessingEmptyLine
= ( pParaPortion
->GetNode()->Len() == 0 );
613 BOOL bEmptyNodeWithPolygon
= ( pParaPortion
->GetNode()->Len() == 0 ) && GetTextRanger();
615 // ---------------------------------------------------------------
616 // Schnelle Sonderbehandlung fuer leere Absaetze...
617 // ---------------------------------------------------------------
618 if ( ( pParaPortion
->GetNode()->Len() == 0 ) && !GetTextRanger() )
620 // schnelle Sonderbehandlung...
621 if ( pParaPortion
->GetTextPortions().Count() )
622 pParaPortion
->GetTextPortions().Reset();
623 if ( pParaPortion
->GetLines().Count() )
624 pParaPortion
->GetLines().Reset();
625 CreateAndInsertEmptyLine( pParaPortion
, nStartPosY
);
626 return FinishCreateLines( pParaPortion
);
629 // ---------------------------------------------------------------
630 // Initialisierung......
631 // ---------------------------------------------------------------
633 // Immer fuer 100% formatieren:
634 sal_Bool bMapChanged
= ImpCheckRefMapMode();
636 if ( pParaPortion
->GetLines().Count() == 0 )
638 EditLine
* pL
= new EditLine
;
639 pParaPortion
->GetLines().Insert( pL
, 0 );
642 // ---------------------------------------------------------------
643 // Absatzattribute holen......
644 // ---------------------------------------------------------------
645 ContentNode
* const pNode
= pParaPortion
->GetNode();
647 BOOL bRightToLeftPara
= IsRightToLeft( nPara
);
649 SvxAdjust eJustification
= GetJustification( nPara
);
650 sal_Bool bHyphenatePara
= ((const SfxBoolItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_HYPHENATE
)).GetValue();
651 sal_Int32 nSpaceBefore
= 0;
652 sal_Int32 nMinLabelWidth
= 0;
653 sal_Int32 nSpaceBeforeAndMinLabelWidth
= GetSpaceBeforeAndMinLabelWidth( pNode
, &nSpaceBefore
, &nMinLabelWidth
);
654 const SvxLRSpaceItem
& rLRItem
= GetLRSpaceItem( pNode
);
655 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&) pNode
->GetContentAttribs().GetItem( EE_PARA_SBL
);
656 const BOOL bScriptSpace
= ((const SvxScriptSpaceItem
&) pNode
->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING
)).GetValue();
658 // const sal_uInt16 nInvalidEnd = ( pParaPortion->GetInvalidDiff() > 0 )
659 // ? pParaPortion->GetInvalidPosStart() + pParaPortion->GetInvalidDiff()
661 const short nInvalidDiff
= pParaPortion
->GetInvalidDiff();
662 const sal_uInt16 nInvalidStart
= pParaPortion
->GetInvalidPosStart();
663 const sal_uInt16 nInvalidEnd
= nInvalidStart
+ Abs( nInvalidDiff
);
665 sal_Bool bQuickFormat
= sal_False
;
666 if ( !bEmptyNodeWithPolygon
&& !HasScriptType( nPara
, i18n::ScriptType::COMPLEX
) )
668 if ( ( pParaPortion
->IsSimpleInvalid() ) && ( nInvalidDiff
> 0 ) &&
669 ( pNode
->Search( CH_FEATURE
, nInvalidStart
) > nInvalidEnd
) )
671 bQuickFormat
= sal_True
;
673 else if ( ( pParaPortion
->IsSimpleInvalid() ) && ( nInvalidDiff
< 0 ) )
675 // pruefen, ob loeschen ueber Portiongrenzen erfolgte...
676 sal_uInt16 nStart
= nInvalidStart
; // DOPPELT !!!!!!!!!!!!!!!
677 sal_uInt16 nEnd
= nStart
- nInvalidDiff
; // neg.
678 bQuickFormat
= sal_True
;
680 sal_uInt16 nPortions
= pParaPortion
->GetTextPortions().Count();
681 for ( sal_uInt16 nTP
= 0; nTP
< nPortions
; nTP
++ )
683 // Es darf kein Start/Ende im geloeschten Bereich liegen.
684 TextPortion
* const pTP
= pParaPortion
->GetTextPortions()[ nTP
];
685 nPos
= nPos
+ pTP
->GetLen();
686 if ( ( nPos
> nStart
) && ( nPos
< nEnd
) )
688 bQuickFormat
= sal_False
;
695 // SW disables TEXT_LAYOUT_COMPLEX_DISABLED, so maybe I have to enable it...
697 // #114278# Saving both layout mode and language (since I'm
698 // potentially changing both)
700 GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE
|PUSH_TEXTLANGUAGE
);
702 ImplInitLayoutMode( GetRefDevice(), nPara
, 0xFFFF );
704 sal_uInt16 nRealInvalidStart
= nInvalidStart
;
706 if ( bEmptyNodeWithPolygon
)
708 TextPortion
* pDummyPortion
= new TextPortion( 0 );
709 pParaPortion
->GetTextPortions().Reset();
710 pParaPortion
->GetTextPortions().Insert( pDummyPortion
, 0 );
712 else if ( bQuickFormat
)
714 // schnellere Methode:
715 RecalcTextPortion( pParaPortion
, nInvalidStart
, nInvalidDiff
);
717 else // nRealInvalidStart kann vor InvalidStart liegen, weil Portions geloescht....
719 CreateTextPortions( pParaPortion
, nRealInvalidStart
);
723 // ---------------------------------------------------------------
724 // Zeile mit InvalidPos suchen, eine Zeile davor beginnen...
725 // Zeilen flaggen => nicht removen !
726 // ---------------------------------------------------------------
728 sal_uInt16 nLine
= pParaPortion
->GetLines().Count()-1;
729 for ( sal_uInt16 nL
= 0; nL
<= nLine
; nL
++ )
731 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nL
);
732 if ( pLine
->GetEnd() > nRealInvalidStart
) // nicht nInvalidStart!
739 // Eine Zeile davor beginnen...
740 // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern.
741 if ( nLine
&& ( !pParaPortion
->IsSimpleInvalid() || ( nInvalidEnd
< pNode
->Len() ) || ( nInvalidDiff
<= 0 ) ) )
744 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nLine
);
746 static Rectangle aZeroArea
= Rectangle( Point(), Point() );
747 Rectangle
aBulletArea( aZeroArea
);
750 aBulletArea
= GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion
) );
751 if ( aBulletArea
.Right() > 0 )
752 pParaPortion
->SetBulletX( (sal_uInt16
) GetXValue( aBulletArea
.Right() ) );
754 pParaPortion
->SetBulletX( 0 ); // Falls Bullet falsch eingestellt.
757 // ---------------------------------------------------------------
758 // Ab hier alle Zeilen durchformatieren...
759 // ---------------------------------------------------------------
760 sal_uInt16 nDelFromLine
= 0xFFFF;
761 sal_Bool bLineBreak
= sal_False
;
763 sal_uInt16 nIndex
= pLine
->GetStart();
764 EditLine
aSaveLine( *pLine
);
765 SvxFont
aTmpFont( pNode
->GetCharAttribs().GetDefFont() );
767 sal_Bool bCalcCharPositions
= sal_True
;
768 sal_Int32
* pBuf
= new sal_Int32
[ pNode
->Len() ];
770 sal_Bool bSameLineAgain
= sal_False
; // Fuer TextRanger, wenn sich die Hoehe aendert.
773 BOOL bForceOneRun
= bEmptyNodeWithPolygon
;
774 BOOL bCompressedChars
= FALSE
;
776 while ( ( nIndex
< pNode
->Len() ) || bForceOneRun
)
778 bForceOneRun
= FALSE
;
780 sal_Bool bEOL
= sal_False
;
781 sal_Bool bEOC
= sal_False
;
782 sal_uInt16 nPortionStart
= 0;
783 sal_uInt16 nPortionEnd
= 0;
785 long nStartX
= GetXValue( rLRItem
.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth
);
788 long nFI
= GetXValue( rLRItem
.GetTxtFirstLineOfst() );
791 if ( !nLine
&& ( pParaPortion
->GetBulletX() > nStartX
) )
793 // TL_NFLR nStartX += nFI; // Vielleicht reicht der LI?
794 // TL_NFLR if ( pParaPortion->GetBulletX() > nStartX )
795 nStartX
= pParaPortion
->GetBulletX();
801 nMaxLineWidth
= aStatus
.AutoPageWidth() ? aMaxAutoPaperSize
.Width() : aPaperSize
.Width();
803 nMaxLineWidth
= aStatus
.AutoPageHeight() ? aMaxAutoPaperSize
.Height() : aPaperSize
.Height();
805 nMaxLineWidth
-= GetXValue( rLRItem
.GetRight() );
806 nMaxLineWidth
-= nStartX
;
808 // Wenn PaperSize == long_max, kann ich keinen neg. Erstzeileneinzug
809 // abziehen (Overflow)
810 if ( ( nMaxLineWidth
< 0 ) && ( nStartX
< 0 ) )
811 nMaxLineWidth
= ( !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height() ) - GetXValue( rLRItem
.GetRight() );
813 // Wenn jetzt noch kleiner 0, kann es nur der rechte Rand sein.
814 if ( nMaxLineWidth
<= 0 )
817 // Problem: Da eine Zeile _vor_ der ungueltigen Position mit der
818 // Formatierung begonnen wird, werden hier leider auch die Positionen
821 // Die Zeile davor kann nur groesser werden, nicht kleiner
823 if ( bCalcCharPositions
)
824 pLine
->GetCharPosArray().Remove( 0, pLine
->GetCharPosArray().Count() );
826 sal_uInt16 nTmpPos
= nIndex
;
827 sal_uInt16 nTmpPortion
= pLine
->GetStartPortion();
829 long nXWidth
= nMaxLineWidth
;
830 if ( nXWidth
<= nTmpWidth
) // while muss 1x durchlaufen werden
831 nXWidth
= nTmpWidth
+1;
833 SvLongsPtr pTextRanges
= 0;
834 long nTextExtraYOffset
= 0;
835 long nTextXOffset
= 0;
836 long nTextLineHeight
= 0;
837 if ( GetTextRanger() )
839 GetTextRanger()->SetVertical( IsVertical() );
841 long nTextY
= nStartPosY
+ GetEditCursor( pParaPortion
, pLine
->GetStart() ).Top();
842 if ( !bSameLineAgain
)
844 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
845 aTmpFont
.SetPhysFont( GetRefDevice() );
846 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
848 if ( IsFixedCellHeight() )
849 nTextLineHeight
= ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
851 nTextLineHeight
= aTmpFont
.GetPhysTxtSize( GetRefDevice(), String() ).Height();
852 // Metriken koennen groesser sein
853 FormatterFontMetric aTempFormatterMetrics
;
854 RecalcFormatterFontMetrics( aTempFormatterMetrics
, aTmpFont
);
855 sal_uInt16 nLineHeight
= aTempFormatterMetrics
.GetHeight();
856 if ( nLineHeight
> nTextLineHeight
)
857 nTextLineHeight
= nLineHeight
;
860 nTextLineHeight
= pLine
->GetHeight();
865 long nYOff
= nTextY
+ nTextExtraYOffset
;
866 long nYDiff
= nTextLineHeight
;
869 long nMaxPolygonX
= GetTextRanger()->GetBoundRect().Right();
870 nYOff
= nMaxPolygonX
-nYOff
;
871 nYDiff
= -nTextLineHeight
;
873 pTextRanges
= GetTextRanger()->GetTextRanges( Range( nYOff
, nYOff
+ nYDiff
) );
874 DBG_ASSERT( pTextRanges
, "GetTextRanges?!" );
875 long nMaxRangeWidth
= 0;
876 // Den breitesten Bereich verwenden...
877 // Der breiteste Bereich koennte etwas verwirren, also
878 // generell den ersten. Am besten mal richtig mit Luecken.
879 // for ( sal_uInt16 n = 0; n < pTextRanges->Count(); )
880 if ( pTextRanges
->Count() )
883 long nA
= pTextRanges
->GetObject( n
++ );
884 long nB
= pTextRanges
->GetObject( n
++ );
885 DBG_ASSERT( nA
<= nB
, "TextRange verdreht?" );
887 if ( nW
> nMaxRangeWidth
)
893 nXWidth
= nMaxRangeWidth
;
895 nMaxLineWidth
= nXWidth
- nStartX
- GetXValue( rLRItem
.GetRight() );
898 // Weiter unten im Polygon versuchen.
899 // Unterhalb des Polygons die Paperbreite verwenden.
900 nTextExtraYOffset
+= Max( (long)(nTextLineHeight
/ 10), (long)1 );
901 if ( ( nTextY
+ nTextExtraYOffset
) > GetTextRanger()->GetBoundRect().Bottom() )
903 nXWidth
= !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height();
904 if ( !nXWidth
) // AutoPaperSize
905 nXWidth
= 0x7FFFFFFF;
911 // Portion suchen, die nicht mehr in Zeile passt....
912 TextPortion
* pPortion
= 0;
913 sal_Bool bBrokenLine
= sal_False
;
914 bLineBreak
= sal_False
;
915 EditCharAttrib
* pNextFeature
= pNode
->GetCharAttribs().FindFeature( pLine
->GetStart() );
916 while ( ( nTmpWidth
< nXWidth
) && !bEOL
&& ( nTmpPortion
< pParaPortion
->GetTextPortions().Count() ) )
918 nPortionStart
= nTmpPos
;
919 pPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
920 if ( pPortion
->GetKind() == PORTIONKIND_HYPHENATOR
)
922 // Portion wegschmeissen, ggf. die davor korrigieren, wenn
923 // die Hyph-Portion ein Zeichen geschluckt hat...
924 pParaPortion
->GetTextPortions().Remove( nTmpPortion
);
925 if ( nTmpPortion
&& pPortion
->GetLen() )
928 TextPortion
* pPrev
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
929 DBG_ASSERT( pPrev
->GetKind() == PORTIONKIND_TEXT
, "Portion?!" );
930 nTmpWidth
-= pPrev
->GetSize().Width();
931 nTmpPos
= nTmpPos
- pPrev
->GetLen();
932 pPrev
->SetLen( pPrev
->GetLen() + pPortion
->GetLen() );
933 pPrev
->GetSize().Width() = (-1);
936 DBG_ASSERT( nTmpPortion
< pParaPortion
->GetTextPortions().Count(), "Keine Portion mehr da!" );
937 pPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
939 DBG_ASSERT( pPortion
->GetKind() != PORTIONKIND_HYPHENATOR
, "CreateLines: Hyphenator-Portion!" );
940 DBG_ASSERT( pPortion
->GetLen() || bProcessingEmptyLine
, "Leere Portion in CreateLines ?!" );
941 if ( pNextFeature
&& ( pNextFeature
->GetStart() == nTmpPos
) )
943 sal_uInt16 nWhich
= pNextFeature
->GetItem()->Which();
948 long nOldTmpWidth
= nTmpWidth
;
951 long nCurPos
= nTmpWidth
+nStartX
;
952 // nCurPos -= rLRItem.GetTxtLeft(); // Tabs relativ zu LI
953 // Skalierung rausrechnen
954 if ( aStatus
.DoStretch() && ( nStretchX
!= 100 ) )
955 nCurPos
= nCurPos
*100/std::max(static_cast<sal_Int32
>(nStretchX
), static_cast<sal_Int32
>(1));
957 short nAllSpaceBeforeText
= static_cast< short >(rLRItem
.GetTxtLeft()/* + rLRItem.GetTxtLeft()*/ + nSpaceBeforeAndMinLabelWidth
);
958 aCurrentTab
.aTabStop
= pNode
->GetContentAttribs().FindTabStop( nCurPos
- nAllSpaceBeforeText
/*rLRItem.GetTxtLeft()*/, aEditDoc
.GetDefTab() );
959 aCurrentTab
.nTabPos
= GetXValue( (long) ( aCurrentTab
.aTabStop
.GetTabPos() + nAllSpaceBeforeText
/*rLRItem.GetTxtLeft()*/ ) );
960 aCurrentTab
.bValid
= FALSE
;
962 // Switch direction in R2L para...
963 if ( bRightToLeftPara
)
965 if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_RIGHT
)
966 aCurrentTab
.aTabStop
.GetAdjustment() = SVX_TAB_ADJUST_LEFT
;
967 else if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_LEFT
)
968 aCurrentTab
.aTabStop
.GetAdjustment() = SVX_TAB_ADJUST_RIGHT
;
971 if ( ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_RIGHT
) ||
972 ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_CENTER
) ||
973 ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL
) )
975 // Bei LEFT/DEFAULT wird dieses Tab nicht mehr betrachtet.
976 aCurrentTab
.bValid
= TRUE
;
977 aCurrentTab
.nStartPosX
= nTmpWidth
;
978 aCurrentTab
.nCharPos
= nTmpPos
;
979 aCurrentTab
.nTabPortion
= nTmpPortion
;
982 pPortion
->GetKind() = PORTIONKIND_TAB
;
983 pPortion
->SetExtraValue( aCurrentTab
.aTabStop
.GetFill() );
984 pPortion
->GetSize().Width() = aCurrentTab
.nTabPos
- (nTmpWidth
+nStartX
);
986 // #90520# Height needed...
987 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
988 pPortion
->GetSize().Height() = aTmpFont
.QuickGetTextSize( GetRefDevice(), String(), 0, 0, NULL
).Height();
990 DBG_ASSERT( pPortion
->GetSize().Width() >= 0, "Tab falsch berechnet!" );
992 nTmpWidth
= aCurrentTab
.nTabPos
-nStartX
;
994 // Wenn dies das erste Token in der Zeile ist,
995 // und nTmpWidth > aPaperSize.Width, habe ich eine
997 if ( ( nTmpWidth
>= nXWidth
) && ( nTmpPortion
== pLine
->GetStartPortion() ) )
1000 // Tab passend machen
1001 pPortion
->GetSize().Width() = nXWidth
-nOldTmpWidth
;
1002 nTmpWidth
= nXWidth
-1;
1004 bBrokenLine
= sal_True
;
1006 pLine
->GetCharPosArray().Insert( pPortion
->GetSize().Width(), nTmpPos
-pLine
->GetStart() );
1007 bCompressedChars
= FALSE
;
1010 case EE_FEATURE_LINEBR
:
1012 DBG_ASSERT( pPortion
, "?!" );
1013 pPortion
->GetSize().Width() = 0;
1015 bLineBreak
= sal_True
;
1016 pPortion
->GetKind() = PORTIONKIND_LINEBREAK
;
1017 bCompressedChars
= FALSE
;
1018 pLine
->GetCharPosArray().Insert( pPortion
->GetSize().Width(), nTmpPos
-pLine
->GetStart() );
1021 case EE_FEATURE_FIELD
:
1023 // long nCurWidth = nTmpWidth;
1024 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
1025 sal_Unicode cChar
= 0; // later: NBS?
1026 aTmpFont
.SetPhysFont( GetRefDevice() );
1027 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
1029 String aFieldValue
= cChar
? String(cChar
) : ((EditCharAttribField
*)pNextFeature
)->GetFieldValue();
1030 if ( bCalcCharPositions
|| !pPortion
->HasValidSize() )
1032 pPortion
->GetSize() = aTmpFont
.QuickGetTextSize( GetRefDevice(), aFieldValue
, 0, aFieldValue
.Len(), 0 );
1033 // Damit kein Scrollen bei ueberlangen Feldern
1034 if ( pPortion
->GetSize().Width() > nXWidth
)
1035 pPortion
->GetSize().Width() = nXWidth
;
1037 nTmpWidth
+= pPortion
->GetSize().Width();
1038 pLine
->GetCharPosArray().Insert( pPortion
->GetSize().Width(), nTmpPos
-pLine
->GetStart() );
1039 pPortion
->GetKind() = cChar
? PORTIONKIND_TEXT
: PORTIONKIND_FIELD
;
1040 // Wenn dies das erste Token in der Zeile ist,
1041 // und nTmpWidth > aPaperSize.Width, habe ich eine
1043 if ( ( nTmpWidth
>= nXWidth
) && ( nTmpPortion
== pLine
->GetStartPortion() ) )
1045 nTmpWidth
= nXWidth
-1;
1047 bBrokenLine
= sal_True
;
1049 // Compression in Fields????
1050 // I think this could be a little bit difficult and is not very usefull
1051 bCompressedChars
= FALSE
;
1054 default: DBG_ERROR( "Was fuer ein Feature ?" );
1056 pNextFeature
= pNode
->GetCharAttribs().FindFeature( pNextFeature
->GetStart() + 1 );
1060 DBG_ASSERT( pPortion
->GetLen() || bProcessingEmptyLine
, "Empty Portion - Extra Space?!" );
1061 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
1062 aTmpFont
.SetPhysFont( GetRefDevice() );
1063 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
1065 if ( bCalcCharPositions
|| !pPortion
->HasValidSize() )
1067 pPortion
->GetSize() = aTmpFont
.QuickGetTextSize( GetRefDevice(), *pParaPortion
->GetNode(), nTmpPos
, pPortion
->GetLen(), pBuf
);
1069 // #i9050# Do Kerning also behind portions...
1070 if ( ( aTmpFont
.GetFixKerning() > 0 ) && ( ( nTmpPos
+ pPortion
->GetLen() ) < pNode
->Len() ) )
1071 pPortion
->GetSize().Width() += aTmpFont
.GetFixKerning();
1072 if ( IsFixedCellHeight() )
1073 pPortion
->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
1075 if ( bCalcCharPositions
)
1077 sal_uInt16 nLen
= pPortion
->GetLen();
1078 // Es wird am Anfang generell das Array geplaettet
1079 // => Immer einfach schnelles insert.
1080 sal_uInt16 nPos
= nTmpPos
- pLine
->GetStart();
1081 pLine
->GetCharPosArray().Insert( pBuf
, nLen
, nPos
);
1084 // And now check for Compression:
1085 if ( pPortion
->GetLen() && GetAsianCompressionMode() )
1086 bCompressedChars
|= ImplCalcAsianCompression( pNode
, pPortion
, nTmpPos
, (sal_Int32
*)pLine
->GetCharPosArray().GetData() + (nTmpPos
-pLine
->GetStart()), 10000, FALSE
);
1088 nTmpWidth
+= pPortion
->GetSize().Width();
1090 pPortion
->SetRightToLeft( GetRightToLeft( nPara
, nTmpPos
+1 ) );
1092 USHORT _nPortionEnd
= nTmpPos
+ pPortion
->GetLen();
1093 if( bScriptSpace
&& ( _nPortionEnd
< pNode
->Len() ) && ( nTmpWidth
< nXWidth
) && IsScriptChange( EditPaM( pNode
, _nPortionEnd
) ) )
1095 BOOL bAllow
= FALSE
;
1096 USHORT nScriptTypeLeft
= GetScriptType( EditPaM( pNode
, _nPortionEnd
) );
1097 USHORT nScriptTypeRight
= GetScriptType( EditPaM( pNode
, _nPortionEnd
+1 ) );
1098 if ( ( nScriptTypeLeft
== i18n::ScriptType::ASIAN
) || ( nScriptTypeRight
== i18n::ScriptType::ASIAN
) )
1101 // No spacing within L2R/R2L nesting
1104 long nExtraSpace
= pPortion
->GetSize().Height()/5;
1105 nExtraSpace
= GetXValue( nExtraSpace
);
1106 pPortion
->GetSize().Width() += nExtraSpace
;
1107 nTmpWidth
+= nExtraSpace
;
1112 if ( aCurrentTab
.bValid
&& ( nTmpPortion
!= aCurrentTab
.nTabPortion
) )
1114 long nWidthAfterTab
= 0;
1115 for ( USHORT n
= aCurrentTab
.nTabPortion
+1; n
<= nTmpPortion
; n
++ )
1117 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( n
);
1118 nWidthAfterTab
+= pTP
->GetSize().Width();
1120 long nW
= nWidthAfterTab
; // Length before tab position
1121 if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_RIGHT
)
1123 // nW = nWidthAfterTab;
1125 else if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_CENTER
)
1127 nW
= nWidthAfterTab
/2;
1129 else if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL
)
1131 // nW = nWidthAfterTab;
1132 String aText
= GetSelected( EditSelection( EditPaM( pParaPortion
->GetNode(), nTmpPos
),
1133 EditPaM( pParaPortion
->GetNode(), nTmpPos
+ pPortion
->GetLen() ) ) );
1134 USHORT nDecPos
= aText
.Search( aCurrentTab
.aTabStop
.GetDecimal() );
1135 if ( nDecPos
!= STRING_NOTFOUND
)
1137 nW
-= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
)->GetSize().Width();
1138 nW
+= aTmpFont
.QuickGetTextSize( GetRefDevice(), *pParaPortion
->GetNode(), nTmpPos
, nDecPos
, NULL
).Width();
1139 aCurrentTab
.bValid
= FALSE
;
1144 DBG_ERROR( "CreateLines: Tab not handled!" );
1146 long nMaxW
= aCurrentTab
.nTabPos
- aCurrentTab
.nStartPosX
- nStartX
;
1150 aCurrentTab
.bValid
= FALSE
;
1152 TextPortion
* pTabPortion
= pParaPortion
->GetTextPortions().GetObject( aCurrentTab
.nTabPortion
);
1153 pTabPortion
->GetSize().Width() = aCurrentTab
.nTabPos
- aCurrentTab
.nStartPosX
- nW
- nStartX
;
1154 nTmpWidth
= aCurrentTab
.nStartPosX
+ pTabPortion
->GetSize().Width() + nWidthAfterTab
;
1157 nTmpPos
= nTmpPos
+ pPortion
->GetLen();
1158 nPortionEnd
= nTmpPos
;
1160 if ( aStatus
.OneCharPerLine() )
1164 DBG_ASSERT( pPortion
, "no portion!?" );
1166 aCurrentTab
.bValid
= FALSE
;
1168 // das war evtl. eine Portion zu weit:
1169 sal_Bool bFixedEnd
= sal_False
;
1170 if ( aStatus
.OneCharPerLine() )
1172 // Zustand vor Portion: ( bis auf nTmpWidth )
1173 nPortionEnd
= nTmpPos
;
1174 nTmpPos
-= pPortion
? pPortion
->GetLen() : 0;
1175 nPortionStart
= nTmpPos
;
1181 // Und jetzt genau ein Zeichen:
1184 nPortionEnd
= nTmpPortion
;
1185 // Eine Nicht-Feature-Portion muss gebrochen werden
1186 if ( pPortion
->GetLen() > 1 )
1188 DBG_ASSERT( pPortion
&& (pPortion
->GetKind() == PORTIONKIND_TEXT
), "Len>1, aber keine TextPortion?" );
1189 nTmpWidth
-= pPortion
? pPortion
->GetSize().Width() : 0;
1190 sal_uInt16 nP
= SplitTextPortion( pParaPortion
, nTmpPos
, pLine
);
1191 TextPortion
* p
= pParaPortion
->GetTextPortions().GetObject( nP
);
1192 DBG_ASSERT( p
, "Portion ?!" );
1193 nTmpWidth
+= p
->GetSize().Width();
1196 else if ( nTmpWidth
>= nXWidth
)
1198 nPortionEnd
= nTmpPos
;
1199 nTmpPos
-= pPortion
? pPortion
->GetLen() : 0;
1200 nPortionStart
= nTmpPos
;
1204 if( pPortion
) switch ( pPortion
->GetKind() )
1206 case PORTIONKIND_TEXT
:
1208 nTmpWidth
-= pPortion
->GetSize().Width();
1211 case PORTIONKIND_FIELD
:
1212 case PORTIONKIND_TAB
:
1214 nTmpWidth
-= pPortion
->GetSize().Width();
1216 bFixedEnd
= sal_True
;
1221 // Ein Feature wird nicht umgebrochen:
1222 DBG_ASSERT( ( pPortion
->GetKind() == PORTIONKIND_LINEBREAK
), "Was fuer ein Feature ?" );
1224 bFixedEnd
= sal_True
;
1232 pLine
->SetEnd( nPortionEnd
);
1233 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "Keine TextPortions?" );
1234 pLine
->SetEndPortion( (sal_uInt16
)pParaPortion
->GetTextPortions().Count() - 1 );
1237 if ( aStatus
.OneCharPerLine() )
1239 pLine
->SetEnd( nPortionEnd
);
1240 pLine
->SetEndPortion( nTmpPortion
-1 );
1242 else if ( bFixedEnd
)
1244 pLine
->SetEnd( nPortionStart
);
1245 pLine
->SetEndPortion( nTmpPortion
-1 );
1247 else if ( bLineBreak
|| bBrokenLine
)
1249 pLine
->SetEnd( nPortionStart
+1 );
1250 pLine
->SetEndPortion( nTmpPortion
-1 );
1251 bEOC
= sal_False
; // wurde oben gesetzt, vielleich mal die if's umstellen?
1255 DBG_ASSERT( pPortion
&& ((nPortionEnd
-nPortionStart
) == pPortion
->GetLen()), "Doch eine andere Portion?!" );
1256 long nRemainingWidth
= nMaxLineWidth
- nTmpWidth
;
1257 sal_Bool bCanHyphenate
= ( aTmpFont
.GetCharSet() != RTL_TEXTENCODING_SYMBOL
);
1258 if ( bCompressedChars
&& pPortion
&& ( pPortion
->GetLen() > 1 ) && pPortion
->GetExtraInfos() && pPortion
->GetExtraInfos()->bCompressed
)
1260 // I need the manipulated DXArray for determining the break postion...
1261 ImplCalcAsianCompression( pNode
, pPortion
, nPortionStart
, const_cast<sal_Int32
*>(( pLine
->GetCharPosArray().GetData() + (nPortionStart
-pLine
->GetStart()) )), 10000, TRUE
);
1264 ImpBreakLine( pParaPortion
, pLine
, pPortion
, nPortionStart
,
1265 nRemainingWidth
, bCanHyphenate
&& bHyphenatePara
);
1268 // ------------------------------------------------------------------
1269 // Zeile fertig => justieren
1270 // ------------------------------------------------------------------
1272 // CalcTextSize sollte besser durch ein kontinuierliches
1273 // Registrieren ersetzt werden !
1274 Size aTextSize
= pLine
->CalcTextSize( *pParaPortion
);
1276 if ( aTextSize
.Height() == 0 )
1278 SeekCursor( pNode
, pLine
->GetStart()+1, aTmpFont
);
1279 aTmpFont
.SetPhysFont( pRefDev
);
1280 ImplInitDigitMode( pRefDev
, 0, 0, 0, aTmpFont
.GetLanguage() );
1282 if ( IsFixedCellHeight() )
1283 aTextSize
.Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
1285 aTextSize
.Height() = aTmpFont
.GetPhysTxtSize( pRefDev
, String() ).Height();
1286 pLine
->SetHeight( (sal_uInt16
)aTextSize
.Height() );
1289 // Die Fontmetriken koennen nicht kontinuierlich berechnet werden,
1290 // wenn der Font sowieso eingestellt ist, weil ggf. ein grosser Font
1291 // erst nach dem Umbrechen ploetzlich in der naechsten Zeile landet
1292 // => Font-Metriken zu gross.
1293 FormatterFontMetric aFormatterMetrics
;
1294 sal_uInt16 nTPos
= pLine
->GetStart();
1295 for ( sal_uInt16 nP
= pLine
->GetStartPortion(); nP
<= pLine
->GetEndPortion(); nP
++ )
1297 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( nP
);
1298 // #95819# problem with hard font height attribute, when everthing but the line break has this attribute
1299 if ( pTP
->GetKind() != PORTIONKIND_LINEBREAK
)
1301 SeekCursor( pNode
, nTPos
+1, aTmpFont
);
1302 aTmpFont
.SetPhysFont( GetRefDevice() );
1303 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
1304 RecalcFormatterFontMetrics( aFormatterMetrics
, aTmpFont
);
1306 nTPos
= nTPos
+ pTP
->GetLen();
1308 sal_uInt16 nLineHeight
= aFormatterMetrics
.GetHeight();
1309 if ( nLineHeight
> pLine
->GetHeight() )
1310 pLine
->SetHeight( nLineHeight
);
1311 pLine
->SetMaxAscent( aFormatterMetrics
.nMaxAscent
);
1313 bSameLineAgain
= sal_False
;
1314 if ( GetTextRanger() && ( pLine
->GetHeight() > nTextLineHeight
) )
1316 // Nochmal mit der anderen Groesse aufsetzen!
1317 bSameLineAgain
= sal_True
;
1321 if ( !bSameLineAgain
&& !aStatus
.IsOutliner() )
1323 if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_MIN
)
1325 sal_uInt16 nMinHeight
= GetYValue( rLSItem
.GetLineHeight() );
1326 sal_uInt16 nTxtHeight
= pLine
->GetHeight();
1327 if ( nTxtHeight
< nMinHeight
)
1329 // Der Ascent muss um die Differenz angepasst werden:
1330 long nDiff
= nMinHeight
- nTxtHeight
;
1331 pLine
->SetMaxAscent( (sal_uInt16
)(pLine
->GetMaxAscent() + nDiff
) );
1332 pLine
->SetHeight( nMinHeight
, nTxtHeight
);
1335 else if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_FIX
)
1337 sal_uInt16 nFixHeight
= GetYValue( rLSItem
.GetLineHeight() );
1338 sal_uInt16 nTxtHeight
= pLine
->GetHeight();
1339 pLine
->SetMaxAscent( (sal_uInt16
)(pLine
->GetMaxAscent() + ( nFixHeight
- nTxtHeight
) ) );
1340 pLine
->SetHeight( nFixHeight
, nTxtHeight
);
1342 else if ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP
)
1344 if ( nPara
|| IsFixedCellHeight() || pLine
->GetStartPortion() ) // Nicht die aller erste Zeile
1346 // #100508# There are documents with PropLineSpace 0, why?
1347 // (cmc: re above question :-) such documents can be seen by importing a .ppt
1348 if ( rLSItem
.GetPropLineSpace() && ( rLSItem
.GetPropLineSpace() != 100 ) )
1350 sal_uInt16 nTxtHeight
= pLine
->GetHeight();
1351 sal_Int32 nH
= nTxtHeight
;
1352 nH
*= rLSItem
.GetPropLineSpace();
1354 // Der Ascent muss um die Differenz angepasst werden:
1355 long nDiff
= pLine
->GetHeight() - nH
;
1356 if ( nDiff
> pLine
->GetMaxAscent() )
1357 nDiff
= pLine
->GetMaxAscent();
1358 pLine
->SetMaxAscent( (sal_uInt16
)(pLine
->GetMaxAscent() - nDiff
) );
1359 pLine
->SetHeight( (sal_uInt16
)nH
, nTxtHeight
);
1366 // #80582# - Bullet should not influence line height
1369 // long nBulletHeight = aBulletArea.GetHeight();
1370 // if ( nBulletHeight > (long)pLine->GetHeight() )
1372 // long nDiff = nBulletHeight - (long)pLine->GetHeight();
1373 // // nDiff auf oben und unten verteilen.
1374 // pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff/2) );
1375 // pLine->SetHeight( (sal_uInt16)nBulletHeight );
1379 if ( ( !IsVertical() && aStatus
.AutoPageWidth() ) ||
1380 ( IsVertical() && aStatus
.AutoPageHeight() ) )
1382 // Wenn die Zeile in die aktuelle Papierbreite passt, muss
1383 // diese Breite fuer die Ausrichting verwendet werden.
1384 // Wenn sie nicht passt oder sie die Papierbreite aendert,
1385 // wird bei Justification != LEFT sowieso noch mal formatiert.
1386 long nMaxLineWidthFix
= ( !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height() )
1387 - GetXValue( rLRItem
.GetRight() ) - nStartX
;
1388 if ( aTextSize
.Width() < nMaxLineWidthFix
)
1389 nMaxLineWidth
= nMaxLineWidthFix
;
1392 if ( bCompressedChars
)
1394 long nRemainingWidth
= nMaxLineWidth
- aTextSize
.Width();
1395 if ( nRemainingWidth
> 0 )
1397 ImplExpandCompressedPortions( pLine
, pParaPortion
, nRemainingWidth
);
1398 aTextSize
= pLine
->CalcTextSize( *pParaPortion
);
1402 if ( pLine
->IsHangingPunctuation() )
1404 // Width from HangingPunctuation was set to 0 in ImpBreakLine,
1405 // check for rel width now, maybe create compression...
1406 long n
= nMaxLineWidth
- aTextSize
.Width();
1407 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( pLine
->GetEndPortion() );
1408 sal_uInt16 nPosInArray
= pLine
->GetEnd()-1-pLine
->GetStart();
1409 long nNewValue
= ( nPosInArray
? pLine
->GetCharPosArray()[ nPosInArray
-1 ] : 0 ) + n
;
1410 pLine
->GetCharPosArray()[ nPosInArray
] = nNewValue
;
1411 pTP
->GetSize().Width() += n
;
1414 pLine
->SetTextWidth( aTextSize
.Width() );
1415 switch ( eJustification
)
1417 case SVX_ADJUST_CENTER
:
1419 long n
= ( nMaxLineWidth
- aTextSize
.Width() ) / 2;
1420 n
+= nStartX
; // Einrueckung bleibt erhalten.
1422 pLine
->SetStartPosX( (sal_uInt16
)n
);
1424 pLine
->SetStartPosX( 0 );
1428 case SVX_ADJUST_RIGHT
:
1430 // Bei automatisch umgebrochenen Zeilen, die ein Blank
1431 // am Ende enthalten, darf das Blank nicht ausgegeben werden!
1433 long n
= nMaxLineWidth
- aTextSize
.Width();
1434 n
+= nStartX
; // Einrueckung bleibt erhalten.
1436 pLine
->SetStartPosX( (sal_uInt16
)n
);
1438 pLine
->SetStartPosX( 0 );
1441 case SVX_ADJUST_BLOCK
:
1443 long nRemainingSpace
= nMaxLineWidth
- aTextSize
.Width();
1444 pLine
->SetStartPosX( (sal_uInt16
)nStartX
);
1445 if ( !bEOC
&& ( nRemainingSpace
> 0 ) ) // nicht die letzte Zeile...
1446 ImpAdjustBlocks( pParaPortion
, pLine
, nRemainingSpace
);
1451 pLine
->SetStartPosX( (sal_uInt16
)nStartX
); // FI, LI
1456 // -----------------------------------------------------------------
1457 // pruefen, ob die Zeile neu ausgegeben werden muss...
1458 // -----------------------------------------------------------------
1459 pLine
->SetInvalid();
1461 // Wenn eine Portion umgebrochen wurde sind ggf. viel zu viele Positionen
1463 if ( bCalcCharPositions
)
1465 sal_uInt16 nLen
= pLine
->GetLen();
1466 sal_uInt16 nCount
= pLine
->GetCharPosArray().Count();
1467 if ( nCount
> nLen
)
1468 pLine
->GetCharPosArray().Remove( nLen
, nCount
-nLen
);
1471 if ( GetTextRanger() )
1474 pLine
->SetStartPosX( (sal_uInt16
) ( pLine
->GetStartPosX() + nTextXOffset
) );
1475 if ( nTextExtraYOffset
)
1477 pLine
->SetHeight( (sal_uInt16
) ( pLine
->GetHeight() + nTextExtraYOffset
), 0, pLine
->GetHeight() );
1478 pLine
->SetMaxAscent( (sal_uInt16
) ( pLine
->GetMaxAscent() + nTextExtraYOffset
) );
1482 // Fuer kleiner 0 noch ueberlegen!
1483 if ( pParaPortion
->IsSimpleInvalid() /* && ( nInvalidDiff > 0 ) */ )
1485 // Aenderung durch einfache Textaenderung...
1486 // Formatierung nicht abbrechen, da Portions evtl. wieder
1487 // gesplittet werden muessen!
1488 // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren!
1489 // Aber ggf. als Valid markieren, damit weniger Ausgabe...
1490 if ( pLine
->GetEnd() < nInvalidStart
)
1492 if ( *pLine
== aSaveLine
)
1499 sal_uInt16 nStart
= pLine
->GetStart();
1500 sal_uInt16 nEnd
= pLine
->GetEnd();
1502 if ( nStart
> nInvalidEnd
)
1504 if ( ( ( nStart
-nInvalidDiff
) == aSaveLine
.GetStart() ) &&
1505 ( ( nEnd
-nInvalidDiff
) == aSaveLine
.GetEnd() ) )
1508 if ( bCalcCharPositions
&& bQuickFormat
)
1510 bCalcCharPositions
= sal_False
;
1511 bLineBreak
= sal_False
;
1512 pParaPortion
->CorrectValuesBehindLastFormattedLine( nLine
);
1517 else if ( bCalcCharPositions
&& bQuickFormat
&& ( nEnd
> nInvalidEnd
) )
1519 // Wenn die ungueltige Zeile so endet, dass die naechste an
1520 // der 'gleichen' Textstelle wie vorher beginnt, also nicht
1521 // anders umgebrochen wird, brauche ich dort auch nicht die
1522 // textbreiten neu bestimmen:
1523 if ( nEnd
== ( aSaveLine
.GetEnd() + nInvalidDiff
) )
1525 bCalcCharPositions
= sal_False
;
1526 bLineBreak
= sal_False
;
1527 pParaPortion
->CorrectValuesBehindLastFormattedLine( nLine
);
1534 if ( !bSameLineAgain
)
1536 nIndex
= pLine
->GetEnd(); // naechste Zeile Start = letzte Zeile Ende
1537 // weil nEnd hinter das letzte Zeichen zeigt!
1539 sal_uInt16 nEndPortion
= pLine
->GetEndPortion();
1541 // Naechste Zeile oder ggf. neue Zeile....
1543 if ( nLine
< pParaPortion
->GetLines().Count()-1 )
1544 pLine
= pParaPortion
->GetLines().GetObject( ++nLine
);
1545 if ( pLine
&& ( nIndex
>= pNode
->Len() ) )
1547 nDelFromLine
= nLine
;
1552 if ( nIndex
< pNode
->Len() )
1554 pLine
= new EditLine
;
1555 pParaPortion
->GetLines().Insert( pLine
, ++nLine
);
1557 else if ( nIndex
&& bLineBreak
&& GetTextRanger() )
1559 // normaly CreateAndInsertEmptyLine would be called, but I want to use
1560 // CreateLines, so I need Polygon code only here...
1561 TextPortion
* pDummyPortion
= new TextPortion( 0 );
1562 pParaPortion
->GetTextPortions().Insert( pDummyPortion
, pParaPortion
->GetTextPortions().Count() );
1563 pLine
= new EditLine
;
1564 pParaPortion
->GetLines().Insert( pLine
, ++nLine
);
1565 bForceOneRun
= TRUE
;
1566 bProcessingEmptyLine
= TRUE
;
1572 pLine
->SetStart( nIndex
);
1573 pLine
->SetEnd( nIndex
);
1574 pLine
->SetStartPortion( nEndPortion
+1 );
1575 pLine
->SetEndPortion( nEndPortion
+1 );
1578 } // while ( Index < Len )
1580 if ( nDelFromLine
!= 0xFFFF )
1581 pParaPortion
->GetLines().DeleteFromLine( nDelFromLine
);
1583 DBG_ASSERT( pParaPortion
->GetLines().Count(), "Keine Zeile nach CreateLines!" );
1585 if ( bLineBreak
== sal_True
)
1586 CreateAndInsertEmptyLine( pParaPortion
, nStartPosY
);
1590 sal_Bool bHeightChanged
= FinishCreateLines( pParaPortion
);
1593 GetRefDevice()->Pop();
1595 GetRefDevice()->Pop();
1597 return bHeightChanged
;
1600 void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion
* pParaPortion
, sal_uInt32
)
1602 DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" );
1604 EditLine
* pTmpLine
= new EditLine
;
1605 pTmpLine
->SetStart( pParaPortion
->GetNode()->Len() );
1606 pTmpLine
->SetEnd( pParaPortion
->GetNode()->Len() );
1607 pParaPortion
->GetLines().Insert( pTmpLine
, pParaPortion
->GetLines().Count() );
1609 sal_Bool bLineBreak
= pParaPortion
->GetNode()->Len() ? sal_True
: sal_False
;
1610 sal_Int32 nSpaceBefore
= 0;
1611 sal_Int32 nSpaceBeforeAndMinLabelWidth
= GetSpaceBeforeAndMinLabelWidth( pParaPortion
->GetNode(), &nSpaceBefore
);
1612 const SvxLRSpaceItem
& rLRItem
= GetLRSpaceItem( pParaPortion
->GetNode() );
1613 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&)pParaPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
1614 short nStartX
= GetXValue( (short)(rLRItem
.GetTxtLeft() + rLRItem
.GetTxtFirstLineOfst() + nSpaceBefore
));
1616 Rectangle aBulletArea
= Rectangle( Point(), Point() );
1617 if ( bLineBreak
== sal_True
)
1619 nStartX
= (short)GetXValue( rLRItem
.GetTxtLeft() + rLRItem
.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth
);
1623 aBulletArea
= GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion
) );
1624 if ( aBulletArea
.Right() > 0 )
1625 pParaPortion
->SetBulletX( (sal_uInt16
) GetXValue( aBulletArea
.Right() ) );
1627 pParaPortion
->SetBulletX( 0 ); // Falls Bullet falsch eingestellt.
1628 if ( pParaPortion
->GetBulletX() > nStartX
)
1630 nStartX
= (short)GetXValue( rLRItem
.GetTxtLeft() + rLRItem
.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth
);
1631 if ( pParaPortion
->GetBulletX() > nStartX
)
1632 nStartX
= pParaPortion
->GetBulletX();
1637 SeekCursor( pParaPortion
->GetNode(), bLineBreak
? pParaPortion
->GetNode()->Len() : 0, aTmpFont
);
1638 aTmpFont
.SetPhysFont( pRefDev
);
1640 TextPortion
* pDummyPortion
= new TextPortion( 0 );
1641 pDummyPortion
->GetSize() = aTmpFont
.GetPhysTxtSize( pRefDev
, String() );
1642 if ( IsFixedCellHeight() )
1643 pDummyPortion
->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
1644 pParaPortion
->GetTextPortions().Insert( pDummyPortion
, pParaPortion
->GetTextPortions().Count() );
1645 FormatterFontMetric aFormatterMetrics
;
1646 RecalcFormatterFontMetrics( aFormatterMetrics
, aTmpFont
);
1647 pTmpLine
->SetMaxAscent( aFormatterMetrics
.nMaxAscent
);
1648 pTmpLine
->SetHeight( (sal_uInt16
) pDummyPortion
->GetSize().Height() );
1649 sal_uInt16 nLineHeight
= aFormatterMetrics
.GetHeight();
1650 if ( nLineHeight
> pTmpLine
->GetHeight() )
1651 pTmpLine
->SetHeight( nLineHeight
);
1653 if ( !aStatus
.IsOutliner() )
1655 USHORT nPara
= GetParaPortions().GetPos( pParaPortion
);
1656 SvxAdjust eJustification
= GetJustification( nPara
);
1657 long nMaxLineWidth
= !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height();
1658 nMaxLineWidth
-= GetXValue( rLRItem
.GetRight() );
1659 long nTextXOffset
= 0;
1660 if ( nMaxLineWidth
< 0 )
1662 if ( eJustification
== SVX_ADJUST_CENTER
)
1663 nStartX
= sal::static_int_cast
< short >(nMaxLineWidth
/ 2);
1664 else if ( eJustification
== SVX_ADJUST_RIGHT
)
1665 nStartX
= sal::static_int_cast
< short >(nMaxLineWidth
);
1667 nStartX
= sal::static_int_cast
< short >(nStartX
+ nTextXOffset
);
1670 pTmpLine
->SetStartPosX( nStartX
);
1672 if ( !aStatus
.IsOutliner() )
1674 if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_MIN
)
1676 sal_uInt16 nMinHeight
= rLSItem
.GetLineHeight();
1677 sal_uInt16 nTxtHeight
= pTmpLine
->GetHeight();
1678 if ( nTxtHeight
< nMinHeight
)
1680 // Der Ascent muss um die Differenz angepasst werden:
1681 long nDiff
= nMinHeight
- nTxtHeight
;
1682 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() + nDiff
) );
1683 pTmpLine
->SetHeight( nMinHeight
, nTxtHeight
);
1686 else if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_FIX
)
1688 sal_uInt16 nFixHeight
= rLSItem
.GetLineHeight();
1689 sal_uInt16 nTxtHeight
= pTmpLine
->GetHeight();
1691 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() + ( nFixHeight
- nTxtHeight
) ) );
1692 pTmpLine
->SetHeight( nFixHeight
, nTxtHeight
);
1694 else if ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP
)
1696 USHORT nPara
= GetParaPortions().GetPos( pParaPortion
);
1697 if ( nPara
|| IsFixedCellHeight() || pTmpLine
->GetStartPortion() ) // Nicht die aller erste Zeile
1699 // #100508# There are documents with PropLineSpace 0, why?
1700 // (cmc: re above question :-) such documents can be seen by importing a .ppt
1701 if ( rLSItem
.GetPropLineSpace() && ( rLSItem
.GetPropLineSpace() != 100 ) )
1703 sal_uInt16 nTxtHeight
= pTmpLine
->GetHeight();
1704 sal_Int32 nH
= nTxtHeight
;
1705 nH
*= rLSItem
.GetPropLineSpace();
1707 // Der Ascent muss um die Differenz angepasst werden:
1708 long nDiff
= pTmpLine
->GetHeight() - nH
;
1709 if ( nDiff
> pTmpLine
->GetMaxAscent() )
1710 nDiff
= pTmpLine
->GetMaxAscent();
1711 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() - nDiff
) );
1712 pTmpLine
->SetHeight( (sal_uInt16
)nH
, nTxtHeight
);
1720 long nMinHeight
= aBulletArea
.GetHeight();
1721 if ( nMinHeight
> (long)pTmpLine
->GetHeight() )
1723 long nDiff
= nMinHeight
- (long)pTmpLine
->GetHeight();
1724 // nDiff auf oben und unten verteilen.
1725 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() + nDiff
/2) );
1726 pTmpLine
->SetHeight( (sal_uInt16
)nMinHeight
);
1731 // -2: Die neue ist bereits eingefuegt.
1733 EditLine
* pLastLine
= pParaPortion
->GetLines().GetObject( pParaPortion
->GetLines().Count()-2 );
1734 DBG_ASSERT( pLastLine
, "Weicher Umbruch, keine Zeile ?!" );
1735 DBG_ASSERT( pLastLine
->GetEnd() == pParaPortion
->GetNode()->Len(), "Doch anders?" );
1737 // pTmpLine->SetStart( pLastLine->GetEnd() );
1738 // pTmpLine->SetEnd( pLastLine->GetEnd() );
1739 sal_uInt16 nPos
= (sal_uInt16
) pParaPortion
->GetTextPortions().Count() - 1 ;
1740 pTmpLine
->SetStartPortion( nPos
);
1741 pTmpLine
->SetEndPortion( nPos
);
1745 sal_Bool
ImpEditEngine::FinishCreateLines( ParaPortion
* pParaPortion
)
1747 // CalcCharPositions( pParaPortion );
1748 pParaPortion
->SetValid();
1749 long nOldHeight
= pParaPortion
->GetHeight();
1750 // sal_uInt16 nPos = GetParaPortions().GetPos( pParaPortion );
1751 // DBG_ASSERT( nPos != USHRT_MAX, "FinishCreateLines: Portion nicht in Liste!" );
1752 // ParaPortion* pPrev = nPos ? GetParaPortions().GetObject( nPos-1 ) : 0;
1753 CalcHeight( pParaPortion
);
1755 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "FinishCreateLines: Keine Text-Portion?" );
1756 sal_Bool bRet
= ( pParaPortion
->GetHeight() != nOldHeight
);
1760 void ImpEditEngine::ImpBreakLine( ParaPortion
* pParaPortion
, EditLine
* pLine
, TextPortion
* pPortion
, sal_uInt16 nPortionStart
, long nRemainingWidth
, sal_Bool bCanHyphenate
)
1762 ContentNode
* const pNode
= pParaPortion
->GetNode();
1764 sal_uInt16 nBreakInLine
= nPortionStart
- pLine
->GetStart();
1765 sal_uInt16 nMax
= nBreakInLine
+ pPortion
->GetLen();
1766 while ( ( nBreakInLine
< nMax
) && ( pLine
->GetCharPosArray()[nBreakInLine
] < nRemainingWidth
) )
1769 sal_uInt16 nMaxBreakPos
= nBreakInLine
+ pLine
->GetStart();
1770 sal_uInt16 nBreakPos
= 0xFFFF;
1772 sal_Bool bCompressBlank
= sal_False
;
1773 sal_Bool bHyphenated
= sal_False
;
1774 sal_Bool bHangingPunctuation
= sal_False
;
1775 sal_Unicode cAlternateReplChar
= 0;
1776 sal_Unicode cAlternateExtraChar
= 0;
1778 if ( ( nMaxBreakPos
< ( nMax
+ pLine
->GetStart() ) ) && ( pNode
->GetChar( nMaxBreakPos
) == ' ' ) )
1780 // Break behind the blank, blank will be compressed...
1781 nBreakPos
= nMaxBreakPos
+ 1;
1782 bCompressBlank
= sal_True
;
1786 sal_uInt16 nMinBreakPos
= pLine
->GetStart();
1787 USHORT nAttrs
= pNode
->GetCharAttribs().GetAttribs().Count();
1788 for ( USHORT nAttr
= nAttrs
; nAttr
; )
1790 EditCharAttrib
* pAttr
= pNode
->GetCharAttribs().GetAttribs()[--nAttr
];
1791 if ( pAttr
->IsFeature() && ( pAttr
->GetEnd() > nMinBreakPos
) && ( pAttr
->GetEnd() <= nMaxBreakPos
) )
1793 nMinBreakPos
= pAttr
->GetEnd();
1798 lang::Locale aLocale
= GetLocale( EditPaM( pNode
, nMaxBreakPos
) );
1800 Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1801 OUString
aText( *pNode
);
1802 Reference
< XHyphenator
> xHyph
;
1803 if ( bCanHyphenate
)
1804 xHyph
= GetHyphenator();
1805 i18n::LineBreakHyphenationOptions
aHyphOptions( xHyph
, Sequence
< PropertyValue
>(), 1 );
1806 i18n::LineBreakUserOptions aUserOptions
;
1808 const i18n::ForbiddenCharacters
* pForbidden
= GetForbiddenCharsTable()->GetForbiddenCharacters( SvxLocaleToLanguage( aLocale
), TRUE
);
1809 aUserOptions
.forbiddenBeginCharacters
= pForbidden
->beginLine
;
1810 aUserOptions
.forbiddenEndCharacters
= pForbidden
->endLine
;
1811 aUserOptions
.applyForbiddenRules
= ((const SfxBoolItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_FORBIDDENRULES
)).GetValue();
1812 aUserOptions
.allowPunctuationOutsideMargin
= ((const SfxBoolItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_HANGINGPUNCTUATION
)).GetValue();
1813 aUserOptions
.allowHyphenateEnglish
= FALSE
;
1815 i18n::LineBreakResults aLBR
= _xBI
->getLineBreak( *pNode
, nMaxBreakPos
, aLocale
, nMinBreakPos
, aHyphOptions
, aUserOptions
);
1816 nBreakPos
= (USHORT
)aLBR
.breakIndex
;
1818 // BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos
1819 if ( nBreakPos
< nMinBreakPos
)
1821 nBreakPos
= nMinBreakPos
;
1823 else if ( ( nBreakPos
> nMaxBreakPos
) && !aUserOptions
.allowPunctuationOutsideMargin
)
1825 DBG_ERROR( "I18N: XBreakIterator::getLineBreak returns position > Max" );
1826 nBreakPos
= nMaxBreakPos
;
1829 // #101795# nBreakPos can never be outside the portion, even not with hangig punctuation
1830 if ( nBreakPos
> nMaxBreakPos
)
1831 nBreakPos
= nMaxBreakPos
;
1833 // BUG in I18N - the japanese dot is in the next line!
1834 // !!! Testen!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1835 if ( (nBreakPos
+ ( aUserOptions
.allowPunctuationOutsideMargin
? 0 : 1 ) ) <= nMaxBreakPos
)
1837 sal_Unicode cFirstInNextLine
= ( (nBreakPos
+1) < pNode
->Len() ) ? pNode
->GetChar( nBreakPos
) : 0;
1838 if ( cFirstInNextLine
== 12290 )
1842 bHangingPunctuation
= ( nBreakPos
> nMaxBreakPos
) ? sal_True
: sal_False
;
1843 pLine
->SetHangingPunctuation( bHangingPunctuation
);
1846 // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
1847 // die Silbentrennung jagen...
1848 // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
1849 // nBreakPos ist der Wort-Anfang
1850 // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
1851 // auf mehr als Zwei Zeilen gebrochen wird...
1852 if ( !bHangingPunctuation
&& bCanHyphenate
&& GetHyphenator().is() )
1854 i18n::Boundary aBoundary
= _xBI
->getWordBoundary( *pNode
, nBreakPos
, GetLocale( EditPaM( pNode
, nBreakPos
) ), ::com::sun::star::i18n::WordType::DICTIONARY_WORD
, sal_True
);
1855 // sal_uInt16 nWordStart = nBreakPos;
1856 // sal_uInt16 nBreakPos_OLD = nBreakPos;
1857 sal_uInt16 nWordStart
= nBreakPos
;
1858 sal_uInt16 nWordEnd
= (USHORT
) aBoundary
.endPos
;
1859 DBG_ASSERT( nWordEnd
> nWordStart
, "ImpBreakLine: Start >= End?" );
1861 USHORT nWordLen
= nWordEnd
- nWordStart
;
1862 if ( ( nWordEnd
>= nMaxBreakPos
) && ( nWordLen
> 3 ) )
1864 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
1865 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
1866 String
aWord( *pNode
, nWordStart
, nWordLen
);
1867 sal_uInt16 nMinTrail
= nWordEnd
-nMaxBreakPos
+1; //+1: Vor dem angeknacksten Buchstaben
1868 Reference
< XHyphenatedWord
> xHyphWord
;
1869 if (xHyphenator
.is())
1870 xHyphWord
= xHyphenator
->hyphenate( aWord
, aLocale
, aWord
.Len() - nMinTrail
, Sequence
< PropertyValue
>() );
1873 sal_Bool bAlternate
= xHyphWord
->isAlternativeSpelling();
1874 sal_uInt16 _nWordLen
= 1 + xHyphWord
->getHyphenPos();
1876 if ( ( _nWordLen
>= 2 ) && ( (nWordStart
+_nWordLen
) >= (pLine
->GetStart() + 2 ) ) )
1880 bHyphenated
= sal_True
;
1881 nBreakPos
= nWordStart
+ _nWordLen
;
1885 String
aAlt( xHyphWord
->getHyphenatedWord() );
1887 // Wir gehen von zwei Faellen aus, die nun
1888 // vorliegen koennen:
1889 // 1) packen wird zu pak-ken
1890 // 2) Schiffahrt wird zu Schiff-fahrt
1891 // In Fall 1 muss ein Zeichen ersetzt werden,
1892 // in Fall 2 wird ein Zeichen hinzugefuegt.
1893 // Die Identifikation wird erschwert durch Worte wie
1894 // "Schiffahrtsbrennesseln", da der Hyphenator alle
1895 // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
1896 // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
1897 // Index des AlternativWord auf aWord schliessen.
1899 // Das ganze geraffel wird durch eine Funktion am
1900 // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
1901 sal_uInt16 nAltStart
= _nWordLen
- 1;
1902 sal_uInt16 nTxtStart
= nAltStart
- (aAlt
.Len() - aWord
.Len());
1903 sal_uInt16 nTxtEnd
= nTxtStart
;
1904 sal_uInt16 nAltEnd
= nAltStart
;
1906 // Die Bereiche zwischen den nStart und nEnd ist
1907 // die Differenz zwischen Alternativ- und OriginalString.
1908 while( nTxtEnd
< aWord
.Len() && nAltEnd
< aAlt
.Len() &&
1909 aWord
.GetChar(nTxtEnd
) != aAlt
.GetChar(nAltEnd
) )
1915 // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
1916 if( nAltEnd
> nTxtEnd
&& nAltStart
== nAltEnd
&&
1917 aWord
.GetChar( nTxtEnd
) == aAlt
.GetChar(nAltEnd
) )
1924 DBG_ASSERT( ( nAltEnd
- nAltStart
) == 1, "Alternate: Falsche Annahme!" );
1926 if ( nTxtEnd
> nTxtStart
)
1927 cAlternateReplChar
= aAlt
.GetChar( nAltStart
);
1929 cAlternateExtraChar
= aAlt
.GetChar( nAltStart
);
1931 bHyphenated
= sal_True
;
1932 nBreakPos
= nWordStart
+ nTxtStart
;
1933 if ( cAlternateReplChar
)
1941 #endif // !SVX_LIGHT
1943 if ( nBreakPos
<= pLine
->GetStart() )
1945 // keine Trenner in Zeile => abhacken !
1946 nBreakPos
= nMaxBreakPos
;
1947 // MT: I18N nextCharacters !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1948 if ( nBreakPos
<= pLine
->GetStart() )
1949 nBreakPos
= pLine
->GetStart() + 1; // Sonst Endlosschleife!
1953 // die angeknackste Portion ist die End-Portion
1954 pLine
->SetEnd( nBreakPos
);
1956 sal_uInt16 nEndPortion
= SplitTextPortion( pParaPortion
, nBreakPos
, pLine
);
1958 if ( !bCompressBlank
&& !bHangingPunctuation
)
1960 // #96187# When justification is not SVX_ADJUST_LEFT, it's important to compress
1961 // the trailing space even if there is enough room for the space...
1962 // Don't check for SVX_ADJUST_LEFT, doesn't matter to compress in this case too...
1963 DBG_ASSERT( nBreakPos
> pLine
->GetStart(), "ImpBreakLines - BreakPos not expected!" );
1964 if ( pNode
->GetChar( nBreakPos
-1 ) == ' ' )
1965 bCompressBlank
= sal_True
;
1968 if ( bCompressBlank
|| bHangingPunctuation
)
1970 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( nEndPortion
);
1971 DBG_ASSERT( pTP
->GetKind() == PORTIONKIND_TEXT
, "BlankRubber: Keine TextPortion!" );
1972 DBG_ASSERT( nBreakPos
> pLine
->GetStart(), "SplitTextPortion am Anfang der Zeile?" );
1973 sal_uInt16 nPosInArray
= nBreakPos
- 1 - pLine
->GetStart();
1974 pTP
->GetSize().Width() = ( nPosInArray
&& ( pTP
->GetLen() > 1 ) ) ? pLine
->GetCharPosArray()[ nPosInArray
-1 ] : 0;
1975 pLine
->GetCharPosArray()[ nPosInArray
] = pTP
->GetSize().Width();
1977 else if ( bHyphenated
)
1979 // Eine Portion fuer den Trenner einbauen...
1980 TextPortion
* pHyphPortion
= new TextPortion( 0 );
1981 pHyphPortion
->GetKind() = PORTIONKIND_HYPHENATOR
;
1982 String
aHyphText( CH_HYPH
);
1983 if ( cAlternateReplChar
)
1985 TextPortion
* pPrev
= pParaPortion
->GetTextPortions().GetObject( nEndPortion
);
1986 DBG_ASSERT( pPrev
&& pPrev
->GetLen(), "Hyphenate: Prev portion?!" );
1987 pPrev
->SetLen( pPrev
->GetLen() - 1 );
1988 pHyphPortion
->SetLen( 1 );
1989 pHyphPortion
->SetExtraValue( cAlternateReplChar
);
1990 // Breite der Portion davor korrigieren:
1991 pPrev
->GetSize().Width() =
1992 pLine
->GetCharPosArray()[ nBreakPos
-1 - pLine
->GetStart() - 1 ];
1994 else if ( cAlternateExtraChar
)
1996 pHyphPortion
->SetExtraValue( cAlternateExtraChar
);
1997 aHyphText
.Insert( cAlternateExtraChar
, 0 );
2000 // Breite der Hyph-Portion ermitteln:
2002 SeekCursor( pParaPortion
->GetNode(), nBreakPos
, aFont
);
2003 aFont
.SetPhysFont( GetRefDevice() );
2004 pHyphPortion
->GetSize().Height() = GetRefDevice()->GetTextHeight();
2005 pHyphPortion
->GetSize().Width() = GetRefDevice()->GetTextWidth( aHyphText
);
2007 pParaPortion
->GetTextPortions().Insert( pHyphPortion
, ++nEndPortion
);
2009 pLine
->SetEndPortion( nEndPortion
);
2012 void ImpEditEngine::ImpAdjustBlocks( ParaPortion
* pParaPortion
, EditLine
* pLine
, long nRemainingSpace
)
2014 DBG_ASSERT( nRemainingSpace
> 0, "AdjustBlocks: Etwas zuwenig..." );
2015 DBG_ASSERT( pLine
, "AdjustBlocks: Zeile ?!" );
2016 if ( ( nRemainingSpace
< 0 ) || pLine
->IsEmpty() )
2019 const USHORT nFirstChar
= pLine
->GetStart();
2020 const USHORT nLastChar
= pLine
->GetEnd() -1; // Last zeigt dahinter
2021 ContentNode
* pNode
= pParaPortion
->GetNode();
2023 DBG_ASSERT( nLastChar
< pNode
->Len(), "AdjustBlocks: Out of range!" );
2025 // Search blanks or Kashidas...
2026 SvUShorts aPositions
;
2028 for ( nChar
= nFirstChar
; nChar
<= nLastChar
; nChar
++ )
2030 if ( pNode
->GetChar(nChar
) == ' ' )
2032 // Don't use blank if language is arabic
2033 LanguageType eLang
= GetLanguage( EditPaM( pNode
, nChar
) );
2034 if ( MsLangId::getPrimaryLanguage( eLang
) != LANGUAGE_ARABIC_PRIMARY_ONLY
)
2035 aPositions
.Insert( nChar
, aPositions
.Count() );
2040 ImpFindKashidas( pNode
, nFirstChar
, nLastChar
, aPositions
);
2043 if ( !aPositions
.Count() )
2046 // Wenn das letzte Zeichen ein Blank ist, will ich es nicht haben!
2047 // Die Breite muss auf die Blocker davor verteilt werden...
2048 // Aber nicht, wenn es das einzige ist
2049 if ( ( pNode
->GetChar( nLastChar
) == ' ' ) && ( aPositions
.Count() > 1 ) && ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode
, nLastChar
) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY
) )
2051 aPositions
.Remove( aPositions
.Count()-1, 1 );
2052 USHORT nPortionStart
, nPortion
;
2053 nPortion
= pParaPortion
->GetTextPortions().FindPortion( nLastChar
+1, nPortionStart
);
2054 TextPortion
* pLastPortion
= pParaPortion
->GetTextPortions()[ nPortion
];
2055 long nRealWidth
= pLine
->GetCharPosArray()[nLastChar
-nFirstChar
];
2056 long nBlankWidth
= nRealWidth
;
2057 if ( nLastChar
> nPortionStart
)
2058 nBlankWidth
-= pLine
->GetCharPosArray()[nLastChar
-nFirstChar
-1];
2059 // Evtl. ist das Blank schon in ImpBreakLine abgezogen worden:
2060 if ( nRealWidth
== pLastPortion
->GetSize().Width() )
2062 // Beim letzten Zeichen muss die Portion hinter dem Blank aufhoeren
2063 // => Korrektur vereinfachen:
2064 DBG_ASSERT( ( nPortionStart
+ pLastPortion
->GetLen() ) == ( nLastChar
+1 ), "Blank doch nicht am Portion-Ende?!" );
2065 pLastPortion
->GetSize().Width() -= nBlankWidth
;
2066 nRemainingSpace
+= nBlankWidth
;
2068 pLine
->GetCharPosArray()[nLastChar
-nFirstChar
] -= nBlankWidth
;
2071 USHORT nGaps
= aPositions
.Count();
2072 const long nMore4Everyone
= nRemainingSpace
/ nGaps
;
2073 long nSomeExtraSpace
= nRemainingSpace
- nMore4Everyone
*nGaps
;
2075 DBG_ASSERT( nSomeExtraSpace
< (long)nGaps
, "AdjustBlocks: ExtraSpace zu gross" );
2076 DBG_ASSERT( nSomeExtraSpace
>= 0, "AdjustBlocks: ExtraSpace < 0 " );
2078 // Die Positionen im Array und die Portion-Breiten korrigieren:
2079 // Letztes Zeichen wird schon nicht mehr beachtet...
2080 for ( USHORT n
= 0; n
< aPositions
.Count(); n
++ )
2082 nChar
= aPositions
[n
];
2083 if ( nChar
< nLastChar
)
2085 USHORT nPortionStart
, nPortion
;
2086 nPortion
= pParaPortion
->GetTextPortions().FindPortion( nChar
, nPortionStart
);
2087 TextPortion
* pLastPortion
= pParaPortion
->GetTextPortions()[ nPortion
];
2089 // Die Breite der Portion:
2090 pLastPortion
->GetSize().Width() += nMore4Everyone
;
2091 if ( nSomeExtraSpace
)
2092 pLastPortion
->GetSize().Width()++;
2094 // Correct positions in array
2095 // Even for kashidas just change positions, VCL will then draw the kashida automaticly
2096 USHORT nPortionEnd
= nPortionStart
+ pLastPortion
->GetLen();
2097 for ( USHORT _n
= nChar
; _n
< nPortionEnd
; _n
++ )
2099 pLine
->GetCharPosArray()[_n
-nFirstChar
] += nMore4Everyone
;
2100 if ( nSomeExtraSpace
)
2101 pLine
->GetCharPosArray()[_n
-nFirstChar
]++;
2104 if ( nSomeExtraSpace
)
2109 // Now the text width contains the extra width...
2110 pLine
->SetTextWidth( pLine
->GetTextWidth() + nRemainingSpace
);
2113 void ImpEditEngine::ImpFindKashidas( ContentNode
* pNode
, USHORT nStart
, USHORT nEnd
, SvUShorts
& rArray
)
2115 // the search has to be performed on a per word base
2117 EditSelection
aWordSel( EditPaM( pNode
, nStart
) );
2118 aWordSel
= SelectWord( aWordSel
, ::com::sun::star::i18n::WordType::DICTIONARY_WORD
);
2119 if ( aWordSel
.Min().GetIndex() < nStart
)
2120 aWordSel
.Min().GetIndex() = nStart
;
2122 while ( ( aWordSel
.Min().GetNode() == pNode
) && ( aWordSel
.Min().GetIndex() < nEnd
) )
2124 USHORT nSavPos
= aWordSel
.Max().GetIndex();
2125 if ( aWordSel
.Max().GetIndex() > nEnd
)
2126 aWordSel
.Max().GetIndex() = nEnd
;
2128 String aWord
= GetSelected( aWordSel
);
2130 // restore selection for proper iteration at the end of the function
2131 aWordSel
.Max().GetIndex() = nSavPos
;
2133 xub_StrLen nIdx
= 0;
2134 xub_StrLen nKashidaPos
= STRING_LEN
;
2136 xub_Unicode cPrevCh
= 0;
2138 while ( nIdx
< aWord
.Len() )
2140 cCh
= aWord
.GetChar( nIdx
);
2143 // after user inserted kashida
2146 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
;
2151 // after a Seen or Sad
2152 if ( nIdx
+ 1 < aWord
.Len() &&
2153 ( 0x633 == cCh
|| 0x635 == cCh
) )
2155 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
;
2160 // before final form of Teh Marbuta, Hah, Dal
2162 // before final form of Alef, Lam or Kaf
2163 if ( nIdx
&& nIdx
+ 1 == aWord
.Len() &&
2164 ( 0x629 == cCh
|| 0x62D == cCh
|| 0x62F == cCh
||
2165 0x627 == cCh
|| 0x644 == cCh
|| 0x643 == cCh
) )
2167 DBG_ASSERT( 0 != cPrevCh
, "No previous character" );
2169 // check if character is connectable to previous character,
2170 if ( lcl_ConnectToPrev( cCh
, cPrevCh
) )
2172 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
- 1;
2179 if ( nIdx
&& nIdx
+ 1 < aWord
.Len() && 0x628 == cCh
)
2181 DBG_ASSERT( 0 != cPrevCh
, "No previous character" );
2183 // check if next character is Reh, Yeh or Alef Maksura
2184 xub_Unicode cNextCh
= aWord
.GetChar( nIdx
+ 1 );
2186 if ( 0x631 == cNextCh
|| 0x64A == cNextCh
||
2189 // check if character is connectable to previous character,
2190 if ( lcl_ConnectToPrev( cCh
, cPrevCh
) )
2191 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
- 1;
2196 // other connecting possibilities
2197 if ( nIdx
&& nIdx
+ 1 == aWord
.Len() &&
2198 0x60C <= cCh
&& 0x6FE >= cCh
)
2200 DBG_ASSERT( 0 != cPrevCh
, "No previous character" );
2202 // check if character is connectable to previous character,
2203 if ( lcl_ConnectToPrev( cCh
, cPrevCh
) )
2205 // only choose this position if we did not find
2207 if ( STRING_LEN
== nKashidaPos
)
2208 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
- 1;
2213 // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
2214 // Damma, Kasra, Shadda and Sukun when checking if
2215 // a character can be connected to previous character.
2216 if ( cCh
< 0x64B || cCh
> 0x652 )
2220 } // end of current word
2222 if ( STRING_LEN
!= nKashidaPos
)
2223 rArray
.Insert( nKashidaPos
, rArray
.Count() );
2225 aWordSel
= WordRight( aWordSel
.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD
);
2226 aWordSel
= SelectWord( aWordSel
, ::com::sun::star::i18n::WordType::DICTIONARY_WORD
);
2230 sal_uInt16
ImpEditEngine::SplitTextPortion( ParaPortion
* pPortion
, sal_uInt16 nPos
, EditLine
* pCurLine
)
2232 DBG_ASSERT( pPortion
, "SplitTextPortion: Welche ?" );
2234 // Die Portion bei nPos wird geplittet, wenn bei nPos nicht
2235 // sowieso ein Wechsel ist
2239 sal_uInt16 nSplitPortion
;
2240 sal_uInt16 nTmpPos
= 0;
2241 TextPortion
* pTextPortion
= 0;
2242 sal_uInt16 nPortions
= pPortion
->GetTextPortions().Count();
2243 for ( nSplitPortion
= 0; nSplitPortion
< nPortions
; nSplitPortion
++ )
2245 TextPortion
* pTP
= pPortion
->GetTextPortions().GetObject(nSplitPortion
);
2246 nTmpPos
= nTmpPos
+ pTP
->GetLen();
2247 if ( nTmpPos
>= nPos
)
2249 if ( nTmpPos
== nPos
) // dann braucht nichts geteilt werden
2251 // Skip Portions with ExtraSpace
2252 // while ( ( (nSplitPortion+1) < nPortions ) && (pPortion->GetTextPortions().GetObject(nSplitPortion+1)->GetKind() == PORTIONKIND_EXTRASPACE ) )
2255 return nSplitPortion
;
2262 DBG_ASSERT( pTextPortion
, "Position ausserhalb des Bereichs!" );
2263 DBG_ASSERT( pTextPortion
->GetKind() == PORTIONKIND_TEXT
, "SplitTextPortion: Keine TextPortion!" );
2265 sal_uInt16 nOverlapp
= nTmpPos
- nPos
;
2266 pTextPortion
->GetLen() = pTextPortion
->GetLen() - nOverlapp
;
2267 TextPortion
* pNewPortion
= new TextPortion( nOverlapp
);
2268 pPortion
->GetTextPortions().Insert( pNewPortion
, nSplitPortion
+1 );
2272 // Kein neues GetTextSize, sondern Werte aus Array verwenden:
2273 DBG_ASSERT( nPos
> pCurLine
->GetStart(), "SplitTextPortion am Anfang der Zeile?" );
2274 pTextPortion
->GetSize().Width() = pCurLine
->GetCharPosArray()[ nPos
-pCurLine
->GetStart()-1 ];
2276 if ( pTextPortion
->GetExtraInfos() && pTextPortion
->GetExtraInfos()->bCompressed
)
2278 // We need the original size from the portion
2279 USHORT nTxtPortionStart
= pPortion
->GetTextPortions().GetStartPos( nSplitPortion
);
2280 SvxFont
aTmpFont( pPortion
->GetNode()->GetCharAttribs().GetDefFont() );
2281 SeekCursor( pPortion
->GetNode(), nTxtPortionStart
+1, aTmpFont
);
2282 aTmpFont
.SetPhysFont( GetRefDevice() );
2283 GetRefDevice()->Push( PUSH_TEXTLANGUAGE
);
2284 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
2285 Size aSz
= aTmpFont
.QuickGetTextSize( GetRefDevice(), *pPortion
->GetNode(), nTxtPortionStart
, pTextPortion
->GetLen(), NULL
);
2286 GetRefDevice()->Pop();
2287 pTextPortion
->GetExtraInfos()->nOrgWidth
= aSz
.Width();
2291 pTextPortion
->GetSize().Width() = (-1);
2293 return nSplitPortion
;
2296 void ImpEditEngine::CreateTextPortions( ParaPortion
* pParaPortion
, sal_uInt16
& rStart
/* , sal_Bool bCreateBlockPortions */ )
2298 sal_uInt16 nStartPos
= rStart
;
2299 ContentNode
* pNode
= pParaPortion
->GetNode();
2300 DBG_ASSERT( pNode
->Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" );
2302 SortedPositions aPositions
;
2303 aPositions
.Insert( (sal_uInt32
) 0 );
2305 sal_uInt16 nAttr
= 0;
2306 EditCharAttrib
* pAttrib
= GetAttrib( pNode
->GetCharAttribs().GetAttribs(), nAttr
);
2309 // Start und Ende in das Array eintragen...
2310 // Die InsertMethode laesst keine doppelten Werte zu....
2311 aPositions
.Insert( pAttrib
->GetStart() );
2312 aPositions
.Insert( pAttrib
->GetEnd() );
2314 pAttrib
= GetAttrib( pNode
->GetCharAttribs().GetAttribs(), nAttr
);
2316 aPositions
.Insert( pNode
->Len() );
2318 if ( !pParaPortion
->aScriptInfos
.Count() )
2319 ((ImpEditEngine
*)this)->InitScriptTypes( GetParaPortions().GetPos( pParaPortion
) );
2321 const ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
2322 for ( USHORT nT
= 0; nT
< rTypes
.Count(); nT
++ )
2323 aPositions
.Insert( rTypes
[nT
].nStartPos
);
2325 const WritingDirectionInfos
& rWritingDirections
= pParaPortion
->aWritingDirectionInfos
;
2326 for ( USHORT nD
= 0; nD
< rWritingDirections
.Count(); nD
++ )
2327 aPositions
.Insert( rWritingDirections
[nD
].nStartPos
);
2329 if ( mpIMEInfos
&& mpIMEInfos
->nLen
&& mpIMEInfos
->pAttribs
&& ( mpIMEInfos
->aPos
.GetNode() == pNode
) )
2331 sal_uInt16 nLastAttr
= 0xFFFF;
2332 for( sal_uInt16 n
= 0; n
< mpIMEInfos
->nLen
; n
++ )
2334 if ( mpIMEInfos
->pAttribs
[n
] != nLastAttr
)
2336 aPositions
.Insert( mpIMEInfos
->aPos
.GetIndex() + n
);
2337 nLastAttr
= mpIMEInfos
->pAttribs
[n
];
2340 aPositions
.Insert( mpIMEInfos
->aPos
.GetIndex() + mpIMEInfos
->nLen
);
2344 // Leider muss die Anzahl der TextPortions mit aPositions.Count()
2345 // nicht uebereinstimmen, da evtl. Zeilenumbrueche...
2346 sal_uInt16 nPortionStart
= 0;
2347 sal_uInt16 nInvPortion
= 0;
2349 for ( nP
= 0; nP
< pParaPortion
->GetTextPortions().Count(); nP
++ )
2351 TextPortion
* pTmpPortion
= pParaPortion
->GetTextPortions().GetObject(nP
);
2352 nPortionStart
= nPortionStart
+ pTmpPortion
->GetLen();
2353 if ( nPortionStart
>= nStartPos
)
2355 nPortionStart
= nPortionStart
- pTmpPortion
->GetLen();
2356 rStart
= nPortionStart
;
2361 DBG_ASSERT( nP
< pParaPortion
->GetTextPortions().Count() || !pParaPortion
->GetTextPortions().Count(), "Nichts zum loeschen: CreateTextPortions" );
2362 if ( nInvPortion
&& ( nPortionStart
+pParaPortion
->GetTextPortions().GetObject(nInvPortion
)->GetLen() > nStartPos
) )
2364 // lieber eine davor...
2365 // Aber nur wenn es mitten in der Portion war, sonst ist es evtl.
2366 // die einzige in der Zeile davor !
2368 nPortionStart
= nPortionStart
- pParaPortion
->GetTextPortions().GetObject(nInvPortion
)->GetLen();
2370 pParaPortion
->GetTextPortions().DeleteFromPortion( nInvPortion
);
2372 // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein:
2373 aPositions
.Insert( nPortionStart
);
2379 aPositions
.Seek_Entry( nPortionStart
, &nInvPos
);
2381 DBG_ASSERT( bFound
&& ( nInvPos
< (aPositions
.Count()-1) ), "InvPos ?!" );
2382 for ( sal_uInt16 i
= nInvPos
+1; i
< aPositions
.Count(); i
++ )
2384 TextPortion
* pNew
= new TextPortion( (sal_uInt16
)aPositions
[i
] - (sal_uInt16
)aPositions
[i
-1] );
2385 pParaPortion
->GetTextPortions().Insert( pNew
, pParaPortion
->GetTextPortions().Count());
2388 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "Keine Portions?!" );
2390 DBG_ASSERT( pParaPortion
->DbgCheckTextPortions(), "Portions kaputt?" );
2394 void ImpEditEngine::RecalcTextPortion( ParaPortion
* pParaPortion
, sal_uInt16 nStartPos
, short nNewChars
)
2396 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "Keine Portions!" );
2397 DBG_ASSERT( nNewChars
, "RecalcTextPortion mit Diff == 0" );
2399 ContentNode
* const pNode
= pParaPortion
->GetNode();
2400 if ( nNewChars
> 0 )
2402 // Wenn an nStartPos ein Attribut beginnt/endet, faengt eine neue Portion
2403 // an, ansonsten wird die Portion an nStartPos erweitert.
2405 if ( pNode
->GetCharAttribs().HasBoundingAttrib( nStartPos
) || IsScriptChange( EditPaM( pNode
, nStartPos
) ) )
2407 sal_uInt16 nNewPortionPos
= 0;
2409 nNewPortionPos
= SplitTextPortion( pParaPortion
, nStartPos
) + 1;
2411 // Eine leere Portion kann hier stehen, wenn der Absatz leer war,
2412 // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist.
2413 if ( ( nNewPortionPos
< pParaPortion
->GetTextPortions().Count() ) &&
2414 !pParaPortion
->GetTextPortions()[nNewPortionPos
]->GetLen() )
2416 DBG_ASSERT( pParaPortion
->GetTextPortions()[nNewPortionPos
]->GetKind() == PORTIONKIND_TEXT
, "Leere Portion war keine TextPortion!" );
2418 pParaPortion
->GetTextPortions()[nNewPortionPos
]->GetLen();
2423 TextPortion
* pNewPortion
= new TextPortion( nNewChars
);
2424 pParaPortion
->GetTextPortions().Insert( pNewPortion
, nNewPortionPos
);
2429 sal_uInt16 nPortionStart
;
2430 const sal_uInt16 nTP
= pParaPortion
->GetTextPortions().
2431 FindPortion( nStartPos
, nPortionStart
);
2432 TextPortion
* const pTP
= pParaPortion
->GetTextPortions()[ nTP
];
2433 DBG_ASSERT( pTP
, "RecalcTextPortion: Portion nicht gefunden" );
2434 pTP
->GetLen() = pTP
->GetLen() + nNewChars
;
2435 pTP
->GetSize().Width() = (-1);
2440 // Portion schrumpfen oder ggf. entfernen.
2441 // Vor Aufruf dieser Methode muss sichergestellt sein, dass
2442 // keine Portions in dem geloeschten Bereich lagen!
2444 // Es darf keine reinragende oder im Bereich startende Portion geben,
2445 // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein
2446 sal_uInt16 nPortion
= 0;
2447 sal_uInt16 nPos
= 0;
2448 sal_uInt16 nEnd
= nStartPos
-nNewChars
;
2449 sal_uInt16 nPortions
= pParaPortion
->GetTextPortions().Count();
2450 TextPortion
* pTP
= 0;
2451 for ( nPortion
= 0; nPortion
< nPortions
; nPortion
++ )
2453 pTP
= pParaPortion
->GetTextPortions()[ nPortion
];
2454 if ( ( nPos
+pTP
->GetLen() ) > nStartPos
)
2456 DBG_ASSERT( nPos
<= nStartPos
, "Start falsch!" );
2457 DBG_ASSERT( nPos
+pTP
->GetLen() >= nEnd
, "End falsch!" );
2460 nPos
= nPos
+ pTP
->GetLen();
2462 DBG_ASSERT( pTP
, "RecalcTextPortion: Portion nicht gefunden" );
2463 if ( ( nPos
== nStartPos
) && ( (nPos
+pTP
->GetLen()) == nEnd
) )
2465 // Portion entfernen;
2466 BYTE nType
= pTP
->GetKind();
2467 pParaPortion
->GetTextPortions().Remove( nPortion
);
2469 if ( nType
== PORTIONKIND_LINEBREAK
)
2471 TextPortion
* pNext
= pParaPortion
->GetTextPortions()[ nPortion
];
2472 if ( pNext
&& !pNext
->GetLen() )
2474 // Dummy-Portion entfernen
2475 pParaPortion
->GetTextPortions().Remove( nPortion
);
2482 DBG_ASSERT( pTP
->GetLen() > (-nNewChars
), "Portion zu klein zum schrumpfen!" );
2483 pTP
->GetLen() = pTP
->GetLen() + nNewChars
;
2486 // ganz am Schluss darf keine HYPHENATOR-Portion stehen bleiben...
2487 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "RecalcTextPortions: Keine mehr da!" );
2488 sal_uInt16 nLastPortion
= pParaPortion
->GetTextPortions().Count() - 1;
2489 pTP
= pParaPortion
->GetTextPortions().GetObject( nLastPortion
);
2490 if ( pTP
->GetKind() == PORTIONKIND_HYPHENATOR
)
2492 // Portion wegschmeissen, ggf. die davor korrigieren, wenn
2493 // die Hyph-Portion ein Zeichen geschluckt hat...
2494 pParaPortion
->GetTextPortions().Remove( nLastPortion
);
2495 if ( nLastPortion
&& pTP
->GetLen() )
2497 TextPortion
* pPrev
= pParaPortion
->GetTextPortions().GetObject( nLastPortion
- 1 );
2498 DBG_ASSERT( pPrev
->GetKind() == PORTIONKIND_TEXT
, "Portion?!" );
2499 pPrev
->SetLen( pPrev
->GetLen() + pTP
->GetLen() );
2500 pPrev
->GetSize().Width() = (-1);
2506 DBG_ASSERT( pParaPortion
->DbgCheckTextPortions(), "Portions kaputt?" );
2510 void ImpEditEngine::SetTextRanger( TextRanger
* pRanger
)
2512 if ( pTextRanger
!= pRanger
)
2515 pTextRanger
= pRanger
;
2517 for ( sal_uInt16 nPara
= 0; nPara
< GetParaPortions().Count(); nPara
++ )
2519 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
2520 pParaPortion
->MarkSelectionInvalid( 0, pParaPortion
->GetNode()->Len() );
2521 pParaPortion
->GetLines().Reset();
2525 UpdateViews( GetActiveView() );
2526 if ( GetUpdateMode() && GetActiveView() )
2527 pActiveView
->ShowCursor( sal_False
, sal_False
);
2531 void ImpEditEngine::SetVertical( BOOL bVertical
)
2533 if ( IsVertical() != bVertical
)
2535 GetEditDoc().SetVertical( bVertical
);
2536 sal_Bool bUseCharAttribs
= ( aStatus
.GetControlWord() & EE_CNTRL_USECHARATTRIBS
) ? sal_True
: sal_False
;
2537 GetEditDoc().CreateDefFont( bUseCharAttribs
);
2538 if ( IsFormatted() )
2541 UpdateViews( GetActiveView() );
2546 void ImpEditEngine::SetFixedCellHeight( BOOL bUseFixedCellHeight
)
2548 if ( IsFixedCellHeight() != bUseFixedCellHeight
)
2550 GetEditDoc().SetFixedCellHeight( bUseFixedCellHeight
);
2551 if ( IsFormatted() )
2554 UpdateViews( GetActiveView() );
2559 void ImpEditEngine::SeekCursor( ContentNode
* pNode
, sal_uInt16 nPos
, SvxFont
& rFont
, OutputDevice
* pOut
, sal_uInt16 nIgnoreWhich
)
2561 // Es war mal geplant, SeekCursor( nStartPos, nEndPos, ... ), damit nur
2562 // ab der StartPosition neu gesucht wird.
2563 // Problem: Es mussten zwei Listen beruecksichtigt/gefuehrt werden:
2564 // OrderedByStart,OrderedByEnd.
2566 if ( nPos
> pNode
->Len() )
2567 nPos
= pNode
->Len();
2569 rFont
= pNode
->GetCharAttribs().GetDefFont();
2571 short nScriptType
= GetScriptType( EditPaM( pNode
, nPos
) );
2572 if ( ( nScriptType
== i18n::ScriptType::ASIAN
) || ( nScriptType
== i18n::ScriptType::COMPLEX
) )
2574 const SvxFontItem
& rFontItem
= (const SvxFontItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTINFO
, nScriptType
) );
2575 rFont
.SetName( rFontItem
.GetFamilyName() );
2576 rFont
.SetFamily( rFontItem
.GetFamily() );
2577 rFont
.SetPitch( rFontItem
.GetPitch() );
2578 rFont
.SetCharSet( rFontItem
.GetCharSet() );
2579 Size
aSz( rFont
.GetSize() );
2580 aSz
.Height() = ((const SvxFontHeightItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTHEIGHT
, nScriptType
) ) ).GetHeight();
2581 rFont
.SetSize( aSz
);
2582 rFont
.SetWeight( ((const SvxWeightItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_WEIGHT
, nScriptType
))).GetWeight() );
2583 rFont
.SetItalic( ((const SvxPostureItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_ITALIC
, nScriptType
))).GetPosture() );
2584 rFont
.SetLanguage( ((const SvxLanguageItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_LANGUAGE
, nScriptType
))).GetLanguage() );
2587 sal_uInt16 nRelWidth
= ((const SvxCharScaleWidthItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH
)).GetValue();
2591 const SvxUnderlineItem
& rTextLineColor
= (const SvxUnderlineItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_UNDERLINE
);
2592 if ( rTextLineColor
.GetColor() != COL_TRANSPARENT
)
2593 pOut
->SetTextLineColor( rTextLineColor
.GetColor() );
2595 pOut
->SetTextLineColor();
2600 const SvxOverlineItem
& rOverlineColor
= (const SvxOverlineItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_OVERLINE
);
2601 if ( rOverlineColor
.GetColor() != COL_TRANSPARENT
)
2602 pOut
->SetOverlineColor( rOverlineColor
.GetColor() );
2604 pOut
->SetOverlineColor();
2607 const SvxLanguageItem
* pCJKLanguageItem
= NULL
;
2609 if ( aStatus
.UseCharAttribs() )
2611 const CharAttribArray
& rAttribs
= pNode
->GetCharAttribs().GetAttribs();
2612 sal_uInt16 nAttr
= 0;
2613 EditCharAttrib
* pAttrib
= GetAttrib( rAttribs
, nAttr
);
2614 while ( pAttrib
&& ( pAttrib
->GetStart() <= nPos
) )
2616 // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen!
2617 // Leere Attribute werden beruecksichtigt( verwendet), da diese
2618 // gerade eingestellt wurden.
2619 // 12.4.95: Doch keine Leeren Attribute verwenden:
2620 // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font
2621 // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam.
2622 if ( ( pAttrib
->Which() != nIgnoreWhich
) &&
2623 ( ( ( pAttrib
->GetStart() < nPos
) && ( pAttrib
->GetEnd() >= nPos
) )
2624 || ( !pNode
->Len() ) ) )
2626 DBG_ASSERT( ( pAttrib
->Which() >= EE_CHAR_START
) && ( pAttrib
->Which() <= EE_FEATURE_END
), "Unglueltiges Attribut in Seek() " );
2627 if ( IsScriptItemValid( pAttrib
->Which(), nScriptType
) )
2629 pAttrib
->SetFont( rFont
, pOut
);
2630 // #i1550# hard color attrib should win over text color from field
2631 if ( pAttrib
->Which() == EE_FEATURE_FIELD
)
2633 EditCharAttrib
* pColorAttr
= pNode
->GetCharAttribs().FindAttrib( EE_CHAR_COLOR
, nPos
);
2635 pColorAttr
->SetFont( rFont
, pOut
);
2638 if ( pAttrib
->Which() == EE_CHAR_FONTWIDTH
)
2639 nRelWidth
= ((const SvxCharScaleWidthItem
*)pAttrib
->GetItem())->GetValue();
2640 if ( pAttrib
->Which() == EE_CHAR_LANGUAGE_CJK
)
2641 pCJKLanguageItem
= (const SvxLanguageItem
*) pAttrib
->GetItem();
2643 pAttrib
= GetAttrib( rAttribs
, ++nAttr
);
2647 if ( !pCJKLanguageItem
)
2648 pCJKLanguageItem
= (const SvxLanguageItem
*) &pNode
->GetContentAttribs().GetItem( EE_CHAR_LANGUAGE_CJK
);
2650 rFont
.SetCJKContextLanguage( pCJKLanguageItem
->GetLanguage() );
2652 if ( rFont
.GetKerning() && IsKernAsianPunctuation() && ( nScriptType
== i18n::ScriptType::ASIAN
) )
2653 rFont
.SetKerning( rFont
.GetKerning() | KERNING_ASIAN
);
2655 if ( aStatus
.DoNotUseColors() )
2657 // Hack fuer DL,weil JOE staendig die Pooldefaults verbiegt!
2658 // const SvxColorItem& rColorItem = (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR );
2659 rFont
.SetColor( /* rColorItem.GetValue() */ COL_BLACK
);
2662 if ( aStatus
.DoStretch() || ( nRelWidth
!= 100 ) )
2664 // Fuer das aktuelle Ausgabegeraet, weil es sonst bei einem
2665 // Drucker als RefDev auf dem Bildschirm #?!@' aussieht!
2666 OutputDevice
* pDev
= pOut
? pOut
: GetRefDevice();
2667 rFont
.SetPhysFont( pDev
);
2668 FontMetric
aMetric( pDev
->GetFontMetric() );
2669 // Fuer die Hoehe nicht die Metriken nehmen, da das bei
2670 // Hoch-/Tiefgestellt schief geht.
2671 Size
aRealSz( aMetric
.GetSize().Width(), rFont
.GetSize().Height() );
2672 if ( aStatus
.DoStretch() )
2674 if ( nStretchY
!= 100 )
2676 aRealSz
.Height() *= nStretchY
;
2677 aRealSz
.Height() /= 100;
2679 if ( nStretchX
!= 100 )
2681 if ( nStretchX
== nStretchY
&&
2684 aRealSz
.Width() = 0;
2688 aRealSz
.Width() *= nStretchX
;
2689 aRealSz
.Width() /= 100;
2691 // Auch das Kerning: (long wegen Zwischenergebnis)
2692 long nKerning
= rFont
.GetFixKerning();
2694 Die Ueberlegung war: Wenn neg. Kerning, aber StretchX = 200
2695 => Nicht das Kerning verdoppelt, also die Buchstaben weiter
2697 ---------------------------
2698 Kern StretchX =>Kern
2699 ---------------------------
2700 >0 <100 < (Proportional)
2701 <0 <100 < (Proportional)
2702 >0 >100 > (Proportional)
2703 <0 >100 < (Der Betrag, also Antiprop)
2705 if ( ( nKerning
< 0 ) && ( nStretchX
> 100 ) )
2709 nKerning
/= nStretchX
;
2711 else if ( nKerning
)
2714 nKerning
*= nStretchX
;
2717 rFont
.SetFixKerning( (short)nKerning
);
2721 if ( nRelWidth
!= 100 )
2723 aRealSz
.Width() *= nRelWidth
;
2724 aRealSz
.Width() /= 100;
2726 rFont
.SetSize( aRealSz
);
2727 // Font wird nicht restauriert...
2730 if ( ( ( rFont
.GetColor() == COL_AUTO
) || ( IsForceAutoColor() ) ) && pOut
)
2732 // #i75566# Do not use AutoColor when printing OR Pdf export
2733 const bool bPrinting(OUTDEV_PRINTER
== pOut
->GetOutDevType());
2734 const bool bPDFExporting(0 != pOut
->GetPDFWriter());
2736 if ( IsAutoColorEnabled() && !bPrinting
&& !bPDFExporting
)
2738 // Never use WindowTextColor on the printer
2739 rFont
.SetColor( GetAutoColor() );
2743 if ( ( GetBackgroundColor() != COL_AUTO
) && GetBackgroundColor().IsDark() )
2744 rFont
.SetColor( COL_WHITE
);
2746 rFont
.SetColor( COL_BLACK
);
2750 if ( mpIMEInfos
&& mpIMEInfos
->pAttribs
&& ( mpIMEInfos
->aPos
.GetNode() == pNode
) &&
2751 ( nPos
> mpIMEInfos
->aPos
.GetIndex() ) && ( nPos
<= ( mpIMEInfos
->aPos
.GetIndex() + mpIMEInfos
->nLen
) ) )
2753 sal_uInt16 nAttr
= mpIMEInfos
->pAttribs
[ nPos
- mpIMEInfos
->aPos
.GetIndex() - 1 ];
2754 if ( nAttr
& EXTTEXTINPUT_ATTR_UNDERLINE
)
2755 rFont
.SetUnderline( UNDERLINE_SINGLE
);
2756 else if ( nAttr
& EXTTEXTINPUT_ATTR_BOLDUNDERLINE
)
2757 rFont
.SetUnderline( UNDERLINE_BOLD
);
2758 else if ( nAttr
& EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE
)
2759 rFont
.SetUnderline( UNDERLINE_DOTTED
);
2760 else if ( nAttr
& EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE
)
2761 rFont
.SetUnderline( UNDERLINE_DOTTED
);
2762 else if ( nAttr
& EXTTEXTINPUT_ATTR_REDTEXT
)
2763 rFont
.SetColor( Color( COL_RED
) );
2764 else if ( nAttr
& EXTTEXTINPUT_ATTR_HALFTONETEXT
)
2765 rFont
.SetColor( Color( COL_LIGHTGRAY
) );
2766 if ( nAttr
& EXTTEXTINPUT_ATTR_HIGHLIGHT
)
2768 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2769 rFont
.SetColor( rStyleSettings
.GetHighlightTextColor() );
2770 rFont
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2771 rFont
.SetTransparent( FALSE
);
2773 else if ( nAttr
& EXTTEXTINPUT_ATTR_GRAYWAVELINE
)
2775 rFont
.SetUnderline( UNDERLINE_WAVE
);
2777 pOut
->SetTextLineColor( Color( COL_LIGHTGRAY
) );
2782 void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric
& rCurMetrics
, SvxFont
& rFont
)
2784 // Fuer Zeilenhoehe bei Hoch/Tief erstmal ohne Propr!
2785 sal_uInt16 nPropr
= rFont
.GetPropr();
2786 DBG_ASSERT( ( nPropr
== 100 ) || rFont
.GetEscapement(), "Propr ohne Escape?!" );
2787 if ( nPropr
!= 100 )
2789 rFont
.SetPropr( 100 );
2790 rFont
.SetPhysFont( pRefDev
);
2792 sal_uInt16 nAscent
, nDescent
;
2794 FontMetric
aMetric( pRefDev
->GetFontMetric() );
2795 nAscent
= (sal_uInt16
)aMetric
.GetAscent();
2796 if ( IsAddExtLeading() )
2797 nAscent
= sal::static_int_cast
< sal_uInt16
>(
2798 nAscent
+ aMetric
.GetExtLeading() );
2799 nDescent
= (sal_uInt16
)aMetric
.GetDescent();
2801 if ( IsFixedCellHeight() )
2803 /* creating correct proportional ascent and descent values lead to problems if different fonts are used
2804 in the same portion, it results in a bigger linespacing.
2805 sal_Int32 f = nAscent + nDescent;
2808 sal_Int32 nHeight = ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() );
2809 nAscent = (sal_Int16)(( nHeight * nAscent ) / f );
2810 nDescent = (sal_Int16)(nHeight - nAscent);
2813 nAscent
= sal::static_int_cast
< sal_uInt16
>( rFont
.GetHeight() );
2814 nDescent
= sal::static_int_cast
< sal_uInt16
>( ImplCalculateFontIndependentLineSpacing( rFont
.GetHeight() ) - nAscent
);
2818 sal_uInt16 nIntLeading
= ( aMetric
.GetIntLeading() > 0 ) ? (sal_uInt16
)aMetric
.GetIntLeading() : 0;
2819 // Fonts ohne Leading bereiten Probleme
2820 if ( ( nIntLeading
== 0 ) && ( pRefDev
->GetOutDevType() == OUTDEV_PRINTER
) )
2822 // Da schaun wir mal, was fuer eine Leading ich auf dem
2823 // Bildschirm erhalte
2824 VirtualDevice
* pVDev
= GetVirtualDevice( pRefDev
->GetMapMode(), pRefDev
->GetDrawMode() );
2825 rFont
.SetPhysFont( pVDev
);
2826 aMetric
= pVDev
->GetFontMetric();
2828 // Damit sich die Leading nicht wieder rausrechnet,
2829 // wenn die ganze Zeile den Font hat, nTmpLeading.
2831 // 4/96: Kommt bei HP Laserjet 4V auch nicht hin
2832 // => Werte komplett vom Bildschirm holen.
2833 // sal_uInt16 nTmpLeading = (sal_uInt16)aMetric.GetLeading();
2834 // nAscent += nTmpLeading;
2835 nAscent
= (sal_uInt16
)aMetric
.GetAscent();
2836 nDescent
= (sal_uInt16
)aMetric
.GetDescent();
2837 // nLeading = (sal_uInt16)aMetric.GetLeading();
2840 if ( nAscent
> rCurMetrics
.nMaxAscent
)
2841 rCurMetrics
.nMaxAscent
= nAscent
;
2842 if ( nDescent
> rCurMetrics
.nMaxDescent
)
2843 rCurMetrics
.nMaxDescent
= nDescent
;
2844 // Sonderbehandlung Hoch/Tief:
2845 if ( rFont
.GetEscapement() )
2847 // Jetzt unter Beruecksichtigung von Escape/Propr
2848 // Ascent oder Descent ggf vergroessern
2849 short nDiff
= (short)(rFont
.GetSize().Height()*rFont
.GetEscapement()/100L);
2850 if ( rFont
.GetEscapement() > 0 )
2852 nAscent
= (sal_uInt16
) (((long)nAscent
)*nPropr
/100 + nDiff
);
2853 if ( nAscent
> rCurMetrics
.nMaxAscent
)
2854 rCurMetrics
.nMaxAscent
= nAscent
;
2856 else // muss < 0 sein
2858 nDescent
= (sal_uInt16
) (((long)nDescent
)*nPropr
/100 - nDiff
);
2859 if ( nDescent
> rCurMetrics
.nMaxDescent
)
2860 rCurMetrics
.nMaxDescent
= nDescent
;
2865 void ImpEditEngine::Paint( OutputDevice
* pOutDev
, Rectangle aClipRec
, Point aStartPos
, sal_Bool bStripOnly
, short nOrientation
)
2867 if ( !GetUpdateMode() && !bStripOnly
)
2870 if ( !IsFormatted() )
2873 long nFirstVisXPos
= - pOutDev
->GetMapMode().GetOrigin().X();
2874 long nFirstVisYPos
= - pOutDev
->GetMapMode().GetOrigin().Y();
2878 Point aRedLineTmpPos
;
2879 DBG_ASSERT( GetParaPortions().Count(), "Keine ParaPortion?!" );
2880 SvxFont
aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() );
2881 Font
aOldFont( pOutDev
->GetFont() );
2882 vcl::PDFExtOutDevData
* pPDFExtOutDevData
= PTR_CAST( vcl::PDFExtOutDevData
, pOutDev
->GetExtOutDevData() );
2884 // Bei gedrehtem Text wird aStartPos als TopLeft angesehen, da andere
2885 // Informationen fehlen, und sowieso das ganze Object ungescrollt
2886 // dargestellt wird.
2887 // Das Rechteck ist unendlich gross.
2888 Point
aOrigin( aStartPos
);
2889 double nCos
= 0.0, nSin
= 0.0;
2892 double nRealOrientation
= nOrientation
*F_PI1800
;
2893 nCos
= cos( nRealOrientation
);
2894 nSin
= sin( nRealOrientation
);
2897 // #110496# Added some more optional metafile comments. This
2898 // change: factored out some duplicated code.
2899 GDIMetaFile
* pMtf
= pOutDev
->GetConnectMetaFile();
2900 const bool bMetafileValid( pMtf
!= NULL
);
2902 // Fuer OnlineSpelling:
2903 // EditPaM aCursorPos;
2904 // if( GetStatus().DoOnlineSpelling() && pActiveView )
2905 // aCurPos = pActiveView->pImpEditView->GetEditSelections().Max();
2907 // --------------------------------------------------
2908 // Ueber alle Absaetze...
2909 // --------------------------------------------------
2910 for ( sal_uInt16 n
= 0; n
< GetParaPortions().Count(); n
++ )
2912 ParaPortion
* pPortion
= GetParaPortions().GetObject( n
);
2913 DBG_ASSERT( pPortion
, "NULL-Pointer in TokenList in Paint" );
2914 // falls beim Tippen Idle-Formatierung, asynchrones Paint.
2915 // Unsichtbare Portions koennen ungueltig sein.
2916 if ( pPortion
->IsVisible() && pPortion
->IsInvalid() )
2919 if ( pPDFExtOutDevData
)
2920 pPDFExtOutDevData
->BeginStructureElement( vcl::PDFWriter::Paragraph
);
2922 long nParaHeight
= pPortion
->GetHeight();
2923 sal_uInt16 nIndex
= 0;
2924 if ( pPortion
->IsVisible() && (
2925 ( !IsVertical() && ( ( aStartPos
.Y() + nParaHeight
) > aClipRec
.Top() ) ) ||
2926 ( IsVertical() && ( ( aStartPos
.X() - nParaHeight
) < aClipRec
.Right() ) ) ) )
2929 // --------------------------------------------------
2930 // Ueber die Zeilen des Absatzes...
2931 // --------------------------------------------------
2932 sal_uInt16 nLines
= pPortion
->GetLines().Count();
2933 sal_uInt16 nLastLine
= nLines
-1;
2935 if ( !IsVertical() )
2936 aStartPos
.Y() += pPortion
->GetFirstLineOffset();
2938 aStartPos
.X() -= pPortion
->GetFirstLineOffset();
2940 Point
aParaStart( aStartPos
);
2942 const SvxLineSpacingItem
& rLSItem
= ((const SvxLineSpacingItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
));
2943 sal_uInt16 nSBL
= ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
)
2944 ? GetYValue( rLSItem
.GetInterLineSpace() ) : 0;
2945 for ( sal_uInt16 nLine
= 0; nLine
< nLines
; nLine
++ )
2947 pLine
= pPortion
->GetLines().GetObject(nLine
);
2948 DBG_ASSERT( pLine
, "NULL-Pointer im Zeileniterator in UpdateViews" );
2949 aTmpPos
= aStartPos
;
2950 if ( !IsVertical() )
2952 aTmpPos
.X() += pLine
->GetStartPosX();
2953 aTmpPos
.Y() += pLine
->GetMaxAscent();
2954 aStartPos
.Y() += pLine
->GetHeight();
2958 aTmpPos
.Y() += pLine
->GetStartPosX();
2959 aTmpPos
.X() -= pLine
->GetMaxAscent();
2960 aStartPos
.X() -= pLine
->GetHeight();
2963 if ( ( !IsVertical() && ( aStartPos
.Y() > aClipRec
.Top() ) )
2964 || ( IsVertical() && aStartPos
.X() < aClipRec
.Right() ) )
2966 // Why not just also call when stripping portions? This will give the correct values
2967 // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call
2968 // PaintBullet correctly; exactly what GetEditEnginePtr()->PaintingFirstLine
2969 // does, too. No change for not-layouting (painting).
2970 if(0 == nLine
) // && !bStripOnly)
2973 GetEditEnginePtr()->PaintingFirstLine( n
, aParaStart
, aTmpPos
.Y(), aOrigin
, nOrientation
, pOutDev
);
2976 // --------------------------------------------------
2977 // Ueber die Portions der Zeile...
2978 // --------------------------------------------------
2979 nIndex
= pLine
->GetStart();
2980 for ( sal_uInt16 y
= pLine
->GetStartPortion(); y
<= pLine
->GetEndPortion(); y
++ )
2982 DBG_ASSERT( pPortion
->GetTextPortions().Count(), "Zeile ohne Textportion im Paint!" );
2983 TextPortion
* pTextPortion
= pPortion
->GetTextPortions().GetObject( y
);
2984 DBG_ASSERT( pTextPortion
, "NULL-Pointer im Portioniterator in UpdateViews" );
2986 long nPortionXOffset
= GetPortionXOffset( pPortion
, pLine
, y
);
2987 if ( !IsVertical() )
2989 aTmpPos
.X() = aStartPos
.X() + nPortionXOffset
;
2990 if ( aTmpPos
.X() > aClipRec
.Right() )
2991 break; // Keine weitere Ausgabe in Zeile noetig
2995 aTmpPos
.Y() = aStartPos
.Y() + nPortionXOffset
;
2996 if ( aTmpPos
.Y() > aClipRec
.Bottom() )
2997 break; // Keine weitere Ausgabe in Zeile noetig
3000 // R2L replaces with obove...
3001 // New position after processing R2L text...
3002 // R2L if ( nR2LWidth && !pTextPortion->GetRightToLeft() )
3004 // R2L if ( !IsVertical() )
3005 // R2L aTmpPos.X() += nR2LWidth;
3007 // R2L aTmpPos.Y() += nR2LWidth;
3009 // R2L nR2LWidth = 0;
3012 switch ( pTextPortion
->GetKind() )
3014 case PORTIONKIND_TEXT
:
3015 case PORTIONKIND_FIELD
:
3016 case PORTIONKIND_HYPHENATOR
:
3018 SeekCursor( pPortion
->GetNode(), nIndex
+1, aTmpFont
, pOutDev
);
3020 BOOL bDrawFrame
= FALSE
;
3022 if ( ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
) && !aTmpFont
.IsTransparent() &&
3023 ( GetBackgroundColor() != COL_AUTO
) && GetBackgroundColor().IsDark() &&
3024 ( IsAutoColorEnabled() && ( pOutDev
->GetOutDevType() != OUTDEV_PRINTER
) ) )
3026 aTmpFont
.SetTransparent( TRUE
);
3027 pOutDev
->SetFillColor();
3028 pOutDev
->SetLineColor( GetAutoColor() );
3033 if ( pTextPortion
->GetKind() == PORTIONKIND_HYPHENATOR
)
3035 aTmpFont
.SetFillColor( COL_LIGHTGRAY
);
3036 aTmpFont
.SetTransparent( sal_False
);
3038 if ( pTextPortion
->GetRightToLeft() )
3040 aTmpFont
.SetFillColor( COL_LIGHTGRAY
);
3041 aTmpFont
.SetTransparent( sal_False
);
3043 else if ( GetScriptType( EditPaM( pPortion
->GetNode(), nIndex
+1 ) ) == i18n::ScriptType::COMPLEX
)
3045 aTmpFont
.SetFillColor( COL_LIGHTCYAN
);
3046 aTmpFont
.SetTransparent( sal_False
);
3049 aTmpFont
.SetPhysFont( pOutDev
);
3051 // #114278# Saving both layout mode and language (since I'm
3052 // potentially changing both)
3053 pOutDev
->Push( PUSH_TEXTLAYOUTMODE
|PUSH_TEXTLANGUAGE
);
3054 ImplInitLayoutMode( pOutDev
, n
, nIndex
);
3055 ImplInitDigitMode( pOutDev
, 0, 0, 0, aTmpFont
.GetLanguage() );
3058 USHORT nTextStart
= 0;
3059 USHORT nTextLen
= 0;
3060 const sal_Int32
* pDXArray
= 0;
3061 sal_Int32
* pTmpDXArray
= 0;
3063 if ( pTextPortion
->GetKind() == PORTIONKIND_TEXT
)
3065 aText
= *pPortion
->GetNode();
3066 nTextStart
= nIndex
;
3067 nTextLen
= pTextPortion
->GetLen();
3068 pDXArray
= pLine
->GetCharPosArray().GetData()+( nIndex
-pLine
->GetStart() );
3070 // --> FME 2005-10-18 #i55716# Paint control characters
3071 if ( aStatus
.MarkFields() )
3074 const xub_StrLen nTmpEnd
= nTextStart
+ pTextPortion
->GetLen();
3076 for ( nTmpIdx
= nTextStart
; nTmpIdx
<= nTmpEnd
; ++nTmpIdx
)
3078 const sal_Unicode cChar
= ( nTmpIdx
!= aText
.Len() && ( nTmpIdx
!= nTextStart
|| 0 == nTextStart
) ) ?
3079 aText
.GetChar( nTmpIdx
) :
3082 if ( 0x200B == cChar
|| 0x2060 == cChar
)
3084 const String
aBlank( ' ' );
3085 long nHalfBlankWidth
= aTmpFont
.QuickGetTextSize( pOutDev
, aBlank
, 0, 1, 0 ).Width() / 2;
3087 const long nAdvanceX
= ( nTmpIdx
== nTmpEnd
?
3088 pTextPortion
->GetSize().Width() :
3089 pDXArray
[ nTmpIdx
- nTextStart
] ) - nHalfBlankWidth
;
3090 const long nAdvanceY
= -pLine
->GetMaxAscent();
3092 Point
aTopLeftRectPos( aTmpPos
);
3093 if ( !IsVertical() )
3095 aTopLeftRectPos
.X() += nAdvanceX
;
3096 aTopLeftRectPos
.Y() += nAdvanceY
;
3100 aTopLeftRectPos
.Y() += nAdvanceX
;
3101 aTopLeftRectPos
.X() -= nAdvanceY
;
3104 Point
aBottomRightRectPos( aTopLeftRectPos
);
3105 if ( !IsVertical() )
3107 aBottomRightRectPos
.X() += 2 * nHalfBlankWidth
;
3108 aBottomRightRectPos
.Y() += pLine
->GetHeight();
3112 aBottomRightRectPos
.X() -= pLine
->GetHeight();
3113 aBottomRightRectPos
.Y() += 2 * nHalfBlankWidth
;
3116 pOutDev
->Push( PUSH_FILLCOLOR
);
3117 pOutDev
->Push( PUSH_LINECOLOR
);
3118 pOutDev
->SetFillColor( COL_LIGHTGRAY
);
3119 pOutDev
->SetLineColor( COL_LIGHTGRAY
);
3121 const Rectangle
aBackRect( aTopLeftRectPos
, aBottomRightRectPos
);
3122 pOutDev
->DrawRect( aBackRect
);
3127 if ( 0x200B == cChar
)
3129 const String
aSlash( '/' );
3130 const short nOldEscapement
= aTmpFont
.GetEscapement();
3131 const BYTE nOldPropr
= aTmpFont
.GetPropr();
3133 aTmpFont
.SetEscapement( -20 );
3134 aTmpFont
.SetPropr( 25 );
3135 aTmpFont
.SetPhysFont( pOutDev
);
3137 const Size aSlashSize
= aTmpFont
.QuickGetTextSize( pOutDev
, aSlash
, 0, 1, 0 );
3138 Point
aSlashPos( aTmpPos
);
3139 const long nAddX
= nHalfBlankWidth
- aSlashSize
.Width() / 2;
3140 if ( !IsVertical() )
3142 aSlashPos
.X() = aTopLeftRectPos
.X() + nAddX
;
3146 aSlashPos
.Y() = aTopLeftRectPos
.Y() + nAddX
;
3149 aTmpFont
.QuickDrawText( pOutDev
, aSlashPos
, aSlash
, 0, 1, 0 );
3151 aTmpFont
.SetEscapement( nOldEscapement
);
3152 aTmpFont
.SetPropr( nOldPropr
);
3153 aTmpFont
.SetPhysFont( pOutDev
);
3160 else if ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
)
3162 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature( nIndex
);
3163 DBG_ASSERT( pAttr
, "Feld nicht gefunden" );
3164 DBG_ASSERT( pAttr
&& pAttr
->GetItem()->ISA( SvxFieldItem
), "Feld vom falschen Typ!" );
3165 aText
= ((EditCharAttribField
*)pAttr
)->GetFieldValue();
3167 nTextLen
= aText
.Len();
3169 pTmpDXArray
= new sal_Int32
[ aText
.Len() ];
3170 pDXArray
= pTmpDXArray
;
3171 Font
_aOldFont( GetRefDevice()->GetFont() );
3172 aTmpFont
.SetPhysFont( GetRefDevice() );
3173 aTmpFont
.QuickGetTextSize( GetRefDevice(), aText
, 0, aText
.Len(), pTmpDXArray
);
3174 if ( aStatus
.DoRestoreFont() )
3175 GetRefDevice()->SetFont( _aOldFont
);
3177 // add a meta file comment if we record to a metafile
3178 if( bMetafileValid
)
3180 SvxFieldItem
* pFieldItem
= PTR_CAST( SvxFieldItem
, pAttr
->GetItem() );
3183 const SvxFieldData
* pFieldData
= pFieldItem
->GetField();
3185 pMtf
->AddAction( pFieldData
->createBeginComment() );
3190 else if ( pTextPortion
->GetKind() == PORTIONKIND_HYPHENATOR
)
3192 if ( pTextPortion
->GetExtraValue() )
3193 aText
= pTextPortion
->GetExtraValue();
3196 nTextLen
= aText
.Len();
3198 // #b6668980# crash when accessing 0 pointer in pDXArray
3199 pTmpDXArray
= new sal_Int32
[ aText
.Len() ];
3200 pDXArray
= pTmpDXArray
;
3201 Font
_aOldFont( GetRefDevice()->GetFont() );
3202 aTmpFont
.SetPhysFont( GetRefDevice() );
3203 aTmpFont
.QuickGetTextSize( GetRefDevice(), aText
, 0, aText
.Len(), pTmpDXArray
);
3204 if ( aStatus
.DoRestoreFont() )
3205 GetRefDevice()->SetFont( _aOldFont
);
3208 long nTxtWidth
= pTextPortion
->GetSize().Width();
3210 Point
aOutPos( aTmpPos
);
3211 aRedLineTmpPos
= aTmpPos
;
3212 // In RTL portions spell markup pos should be at the start of the
3213 // first chara as well. That is on the right end of the portion
3214 if (pTextPortion
->IsRightToLeft())
3215 aRedLineTmpPos
.X() += pTextPortion
->GetSize().Width();
3217 //L2R if ( pTextPortion->GetRightToLeft() )
3219 //L2R sal_uInt16 nNextPortion = y+1;
3220 //L2R while ( nNextPortion <= pLine->GetEndPortion() )
3222 //L2R TextPortion* pNextTextPortion = pPortion->GetTextPortions().GetObject( nNextPortion );
3223 //L2R if ( pNextTextPortion->GetRightToLeft() )
3225 //L2R if ( !IsVertical() )
3226 //L2R aOutPos.X() += pNextTextPortion->GetSize().Width();
3228 //L2R aOutPos.Y() += pNextTextPortion->GetSize().Width();
3232 //L2R nNextPortion++;
3237 EEngineData::WrongSpellVector aWrongSpellVector
;
3239 if(GetStatus().DoOnlineSpelling() && pTextPortion
->GetLen())
3241 WrongList
* pWrongs
= pPortion
->GetNode()->GetWrongList();
3243 if(pWrongs
&& pWrongs
->HasWrongs())
3245 sal_uInt16
nStart(nIndex
);
3247 sal_Bool
bWrong(pWrongs
->NextWrong(nStart
, nEnd
));
3248 const sal_uInt16
nMaxEnd(nIndex
+ pTextPortion
->GetLen());
3252 if(nStart
>= nMaxEnd
)
3268 aWrongSpellVector
.push_back(EEngineData::WrongSpellClass(nStart
, nEnd
));
3275 bWrong
= pWrongs
->NextWrong(nStart
, nEnd
);
3285 const SvxFieldData
* pFieldData
= 0;
3287 if(PORTIONKIND_FIELD
== pTextPortion
->GetKind())
3289 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature(nIndex
);
3290 SvxFieldItem
* pFieldItem
= PTR_CAST(SvxFieldItem
, pAttr
->GetItem());
3294 pFieldData
= pFieldItem
->GetField();
3298 // support for EOC, EOW, EOS TEXT comments. To support that,
3299 // the locale is needed. With the locale and a XBreakIterator it is
3300 // possible to re-create the text marking info on primitive level
3301 const lang::Locale
aLocale(GetLocale(EditPaM(pPortion
->GetNode(), nIndex
+ 1)));
3303 // create EOL and EOP bools
3304 const bool bEndOfLine(y
== pLine
->GetEndPortion());
3305 const bool bEndOfParagraph(bEndOfLine
&& nLine
+ 1 == nLines
);
3307 // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in
3308 // consequence, but also already set at pOutDev)
3309 const Color
aOverlineColor(pOutDev
->GetOverlineColor());
3311 // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in
3312 // consequence, but also already set at pOutDev)
3313 const Color
aTextLineColor(pOutDev
->GetTextLineColor());
3315 // Unicode code points conversion according to ctl text numeral setting
3316 ImplInitDigitMode( 0, &aText
, nTextStart
, nTextLen
, aTmpFont
.GetLanguage() );
3318 // StripPortions() data callback
3319 GetEditEnginePtr()->DrawingText( aOutPos
, aText
, nTextStart
, nTextLen
, pDXArray
,
3320 aTmpFont
, n
, nIndex
, pTextPortion
->GetRightToLeft(),
3321 aWrongSpellVector
.size() ? &aWrongSpellVector
: 0,
3323 bEndOfLine
, bEndOfParagraph
, false, // support for EOL/EOP TEXT comments
3330 short nEsc
= aTmpFont
.GetEscapement();
3333 // Bei Hoch/Tief selbst Hand anlegen:
3334 if ( aTmpFont
.GetEscapement() )
3336 long nDiff
= aTmpFont
.GetSize().Height() * aTmpFont
.GetEscapement() / 100L;
3337 if ( !IsVertical() )
3338 aOutPos
.Y() -= nDiff
;
3340 aOutPos
.X() += nDiff
;
3341 aRedLineTmpPos
= aOutPos
;
3342 aTmpFont
.SetEscapement( 0 );
3345 aOutPos
= lcl_ImplCalcRotatedPos( aOutPos
, aOrigin
, nSin
, nCos
);
3346 aTmpFont
.SetOrientation( aTmpFont
.GetOrientation()+nOrientation
);
3347 aTmpFont
.SetPhysFont( pOutDev
);
3350 // nur ausgeben, was im sichtbaren Bereich beginnt:
3351 // Wichtig, weil Bug bei einigen Grafikkarten bei transparentem Font, Ausgabe bei neg.
3352 if ( nOrientation
|| ( !IsVertical() && ( ( aTmpPos
.X() + nTxtWidth
) >= nFirstVisXPos
) )
3353 || ( IsVertical() && ( ( aTmpPos
.Y() + nTxtWidth
) >= nFirstVisYPos
) ) )
3355 if ( nEsc
&& ( ( aTmpFont
.GetUnderline() != UNDERLINE_NONE
) ) )
3357 // Das Hoch/Tief ohne Underline malen, das Underline
3358 // auf der BaseLine der Original-Fonthoehe ausgeben...
3360 // Aber nur, wenn davor auch Unterstrichen!
3361 sal_Bool bSpecialUnderline
= sal_False
;
3362 EditCharAttrib
* pPrev
= pPortion
->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT
, nIndex
);
3366 // Unterstreichung davor?
3367 if ( pPrev
->GetStart() )
3369 SeekCursor( pPortion
->GetNode(), pPrev
->GetStart(), aDummy
);
3370 if ( aDummy
.GetUnderline() != UNDERLINE_NONE
)
3371 bSpecialUnderline
= sal_True
;
3373 if ( !bSpecialUnderline
&& ( pPrev
->GetEnd() < pPortion
->GetNode()->Len() ) )
3375 SeekCursor( pPortion
->GetNode(), pPrev
->GetEnd()+1, aDummy
);
3376 if ( aDummy
.GetUnderline() != UNDERLINE_NONE
)
3377 bSpecialUnderline
= sal_True
;
3380 if ( bSpecialUnderline
)
3382 Size aSz
= aTmpFont
.GetPhysTxtSize( pOutDev
, aText
, nTextStart
, nTextLen
);
3383 BYTE nProp
= aTmpFont
.GetPropr();
3384 aTmpFont
.SetEscapement( 0 );
3385 aTmpFont
.SetPropr( 100 );
3386 aTmpFont
.SetPhysFont( pOutDev
);
3388 aBlanks
.Fill( nTextLen
, ' ' );
3389 Point
aUnderlinePos( aOutPos
);
3391 aUnderlinePos
= lcl_ImplCalcRotatedPos( aTmpPos
, aOrigin
, nSin
, nCos
);
3392 pOutDev
->DrawStretchText( aUnderlinePos
, aSz
.Width(), aBlanks
, 0, nTextLen
);
3394 aTmpFont
.SetUnderline( UNDERLINE_NONE
);
3395 if ( !nOrientation
)
3396 aTmpFont
.SetEscapement( nEsc
);
3397 aTmpFont
.SetPropr( nProp
);
3398 aTmpFont
.SetPhysFont( pOutDev
);
3401 Point
aRealOutPos( aOutPos
);
3402 if ( ( pTextPortion
->GetKind() == PORTIONKIND_TEXT
)
3403 && pTextPortion
->GetExtraInfos() && pTextPortion
->GetExtraInfos()->bCompressed
3404 && pTextPortion
->GetExtraInfos()->bFirstCharIsRightPunktuation
)
3406 aRealOutPos
.X() += pTextPortion
->GetExtraInfos()->nPortionOffsetX
;
3409 // --> FME 2005-06-17 #i37132# RTL portions with
3410 // compressed blank should not paint this blank:
3411 if ( pTextPortion
->IsRightToLeft() && nTextLen
>= 2 &&
3412 pDXArray
[ nTextLen
- 1 ] ==
3413 pDXArray
[ nTextLen
- 2 ] &&
3414 ' ' == aText
.GetChar( nTextStart
+ nTextLen
- 1 ) )
3419 aTmpFont
.QuickDrawText( pOutDev
, aRealOutPos
, aText
, nTextStart
, nTextLen
, pDXArray
);
3423 Point
aTopLeft( aTmpPos
);
3424 aTopLeft
.Y() -= pLine
->GetMaxAscent();
3426 aTopLeft
= lcl_ImplCalcRotatedPos( aTopLeft
, aOrigin
, nSin
, nCos
);
3427 Rectangle
aRect( aTopLeft
, pTextPortion
->GetSize() );
3428 pOutDev
->DrawRect( aRect
);
3433 if ( pPDFExtOutDevData
)
3435 if ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
)
3437 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature( nIndex
);
3438 SvxFieldItem
* pFieldItem
= PTR_CAST( SvxFieldItem
, pAttr
->GetItem() );
3441 const SvxFieldData
* pFieldData
= pFieldItem
->GetField();
3442 if ( pFieldData
->ISA( SvxURLField
) )
3444 Point
aTopLeft( aTmpPos
);
3445 aTopLeft
.Y() -= pLine
->GetMaxAscent();
3446 // if ( nOrientation )
3447 // aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos );
3449 Rectangle
aRect( aTopLeft
, pTextPortion
->GetSize() );
3450 vcl::PDFExtOutDevBookmarkEntry aBookmark
;
3451 aBookmark
.nLinkId
= pPDFExtOutDevData
->CreateLink( aRect
);
3452 aBookmark
.aBookmark
= ((SvxURLField
*)pFieldData
)->GetURL();
3453 std::vector
< vcl::PDFExtOutDevBookmarkEntry
>& rBookmarks
= pPDFExtOutDevData
->GetBookmarks();
3454 rBookmarks
.push_back( aBookmark
);
3468 if ( GetStatus().DoOnlineSpelling() && pPortion
->GetNode()->GetWrongList()->HasWrongs() && pTextPortion
->GetLen() )
3470 {//#105750# adjust LinePos for superscript or subscript text
3471 short _nEsc
= aTmpFont
.GetEscapement();
3474 long nShift
= ((_nEsc
*long(aTmpFont
.GetSize().Height()))/ 100L);
3476 aRedLineTmpPos
.Y() -= nShift
;
3478 aRedLineTmpPos
.X() += nShift
;
3481 Color
aOldColor( pOutDev
->GetLineColor() );
3482 pOutDev
->SetLineColor( Color( GetColorConfig().GetColorValue( svtools::SPELL
).nColor
) );
3483 lcl_DrawRedLines( pOutDev
, aTmpFont
.GetSize().Height(), aRedLineTmpPos
, nIndex
, nIndex
+ pTextPortion
->GetLen(), pDXArray
, pPortion
->GetNode()->GetWrongList(), nOrientation
, aOrigin
, IsVertical(), pTextPortion
->IsRightToLeft() );
3484 pOutDev
->SetLineColor( aOldColor
);
3486 #endif // !SVX_LIGHT
3492 delete[] pTmpDXArray
;
3494 // R2L if ( !pTextPortion->GetRightToLeft() )
3496 // R2L if ( !IsVertical() )
3497 // R2L aTmpPos.X() += nTxtWidth;
3499 // R2L aTmpPos.Y() += nTxtWidth;
3503 // R2L nR2LWidth += nTxtWidth;
3506 if ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
)
3508 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature( nIndex
);
3509 DBG_ASSERT( pAttr
, "Feld nicht gefunden" );
3510 DBG_ASSERT( pAttr
&& pAttr
->GetItem()->ISA( SvxFieldItem
), "Feld vom falschen Typ!" );
3512 // add a meta file comment if we record to a metafile
3513 if( bMetafileValid
)
3515 SvxFieldItem
* pFieldItem
= PTR_CAST( SvxFieldItem
, pAttr
->GetItem() );
3519 const SvxFieldData
* pFieldData
= pFieldItem
->GetField();
3521 pMtf
->AddAction( pFieldData
->createEndComment() );
3529 // case PORTIONKIND_EXTRASPACE:
3530 case PORTIONKIND_TAB
:
3532 if ( pTextPortion
->GetExtraValue() && ( pTextPortion
->GetExtraValue() != ' ' ) )
3534 SeekCursor( pPortion
->GetNode(), nIndex
+1, aTmpFont
, pOutDev
);
3535 aTmpFont
.SetTransparent( sal_False
);
3536 aTmpFont
.SetEscapement( 0 );
3537 aTmpFont
.SetPhysFont( pOutDev
);
3538 long nCharWidth
= aTmpFont
.QuickGetTextSize( pOutDev
, pTextPortion
->GetExtraValue(), 0, 1, NULL
).Width();
3541 nChars
= pTextPortion
->GetSize().Width() / nCharWidth
;
3543 nChars
= 2; // wird durch DrawStretchText gestaucht.
3544 else if ( nChars
== 2 )
3545 nChars
= 3; // sieht besser aus
3548 aText
.Fill( (USHORT
)nChars
, pTextPortion
->GetExtraValue() );
3549 pOutDev
->DrawStretchText( aTmpPos
, pTextPortion
->GetSize().Width(), aText
);
3554 nIndex
= nIndex
+ pTextPortion
->GetLen();
3558 if ( ( nLine
!= nLastLine
) && !aStatus
.IsOutliner() )
3560 if ( !IsVertical() )
3561 aStartPos
.Y() += nSBL
;
3563 aStartPos
.X() -= nSBL
;
3566 // keine sichtbaren Aktionen mehr?
3567 if ( !IsVertical() && ( aStartPos
.Y() >= aClipRec
.Bottom() ) )
3569 else if ( IsVertical() && ( aStartPos
.X() <= aClipRec
.Left() ) )
3573 if ( !aStatus
.IsOutliner() )
3575 const SvxULSpaceItem
& rULItem
= (const SvxULSpaceItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
3576 long nUL
= GetYValue( rULItem
.GetLower() );
3577 if ( !IsVertical() )
3578 aStartPos
.Y() += nUL
;
3580 aStartPos
.X() -= nUL
;
3585 if ( !IsVertical() )
3586 aStartPos
.Y() += nParaHeight
;
3588 aStartPos
.X() -= nParaHeight
;
3591 if ( pPDFExtOutDevData
)
3592 pPDFExtOutDevData
->EndStructureElement();
3594 // keine sichtbaren Aktionen mehr?
3595 if ( !IsVertical() && ( aStartPos
.Y() > aClipRec
.Bottom() ) )
3597 if ( IsVertical() && ( aStartPos
.X() < aClipRec
.Left() ) )
3600 if ( aStatus
.DoRestoreFont() )
3601 pOutDev
->SetFont( aOldFont
);
3604 void ImpEditEngine::Paint( ImpEditView
* pView
, const Rectangle
& rRec
, sal_Bool bUseVirtDev
)
3606 DBG_ASSERT( pView
, "Keine View - Kein Paint!" );
3607 DBG_CHKOBJ( GetEditEnginePtr(), EditEngine
, 0 );
3609 if ( !GetUpdateMode() || IsInUndo() )
3612 // Schnittmenge aus Paintbereich und OutputArea.
3613 Rectangle
aClipRec( pView
->GetOutputArea() );
3614 aClipRec
.Intersection( rRec
);
3616 Window
* pOutWin
= pView
->GetWindow();
3620 Rectangle
aClipRecPixel( pOutWin
->LogicToPixel( aClipRec
) );
3621 if ( !IsVertical() )
3623 // etwas mehr, falls abgerundet!
3624 aClipRecPixel
.Right() += 1;
3625 aClipRecPixel
.Bottom() += 1;
3629 aClipRecPixel
.Left() -= 1;
3630 aClipRecPixel
.Bottom() += 1;
3633 // Wenn aClipRecPixel > XXXX, dann invalidieren ?!
3635 VirtualDevice
* pVDev
= GetVirtualDevice( pOutWin
->GetMapMode(), pOutWin
->GetDrawMode() );
3636 pVDev
->SetDigitLanguage( GetRefDevice()->GetDigitLanguage() );
3639 Color
aBackgroundColor( pView
->GetBackgroundColor() );
3640 // #i47161# Check if text is visible on background
3642 ContentNode
* pNode
= GetEditDoc().SaveGetObject( 0 );
3643 SeekCursor( pNode
, 1, aTmpFont
);
3644 Color
aFontColor( aTmpFont
.GetColor() );
3645 if( aFontColor
== COL_AUTO
)
3646 aFontColor
= GetAutoColor();
3648 // #i69346# check for reverse color of input method attribute
3649 if( mpIMEInfos
&& (mpIMEInfos
->aPos
.GetNode() == pNode
&&
3650 mpIMEInfos
->pAttribs
))
3652 sal_uInt16 nAttr
= mpIMEInfos
->pAttribs
[ 0 ];
3653 if ( nAttr
& EXTTEXTINPUT_ATTR_HIGHLIGHT
)
3655 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
3656 aFontColor
= rStyleSettings
.GetHighlightColor() ;
3660 UINT8 nColorDiff
= aFontColor
.GetColorError( aBackgroundColor
);
3661 if( nColorDiff
< 8 )
3662 aBackgroundColor
= aFontColor
.IsDark() ? COL_WHITE
: COL_BLACK
;
3663 pVDev
->SetBackground( aBackgroundColor
);
3666 sal_Bool bVDevValid
= sal_True
;
3667 Size
aOutSz( pVDev
->GetOutputSizePixel() );
3668 if ( ( aOutSz
.Width() < aClipRecPixel
.GetWidth() ) ||
3669 ( aOutSz
.Height() < aClipRecPixel
.GetHeight() ) )
3671 bVDevValid
= pVDev
->SetOutputSizePixel( aClipRecPixel
.GetSize() );
3675 // Das VirtDev kann bei einem Resize sehr gross werden =>
3676 // irgendwann mal kleiner machen!
3677 if ( ( aOutSz
.Height() > ( aClipRecPixel
.GetHeight() + RESDIFF
) ) ||
3678 ( aOutSz
.Width() > ( aClipRecPixel
.GetWidth() + RESDIFF
) ) )
3680 bVDevValid
= pVDev
->SetOutputSizePixel( aClipRecPixel
.GetSize() );
3687 DBG_ASSERT( bVDevValid
, "VDef konnte nicht vergroessert werden!" );
3690 Paint( pView
, rRec
, sal_False
/* ohne VDev */ );
3694 // PaintRect fuer VDev nicht mit alignter Groesse,
3695 // da sonst die Zeile darunter auch ausgegeben werden muss:
3696 Rectangle
aTmpRec( Point( 0, 0 ), aClipRec
.GetSize() );
3698 aClipRec
= pOutWin
->PixelToLogic( aClipRecPixel
);
3700 if ( !IsVertical() )
3702 aStartPos
= aClipRec
.TopLeft();
3703 aStartPos
= pView
->GetDocPos( aStartPos
);
3704 aStartPos
.X() *= (-1);
3705 aStartPos
.Y() *= (-1);
3709 aStartPos
= aClipRec
.TopRight();
3710 Point
aDocPos( pView
->GetDocPos( aStartPos
) );
3711 aStartPos
.X() = aClipRec
.GetSize().Width() + aDocPos
.Y();
3712 aStartPos
.Y() = -aDocPos
.X();
3715 Paint( pVDev
, aTmpRec
, aStartPos
);
3717 sal_Bool bClipRegion
= sal_False
;
3719 MapMode aOldMapMode
;
3720 if ( GetTextRanger() )
3722 // Some problems here with push/pop, why?!
3723 // pOutWin->Push( PUSH_CLIPREGION|PUSH_MAPMODE );
3724 bClipRegion
= pOutWin
->IsClipRegion();
3725 aOldRegion
= pOutWin
->GetClipRegion();
3726 // Wie bekomme ich das Polygon an die richtige Stelle????
3727 // Das Polygon bezieht sich auf die View, nicht auf das Window
3728 // => Origin umsetzen...
3729 aOldMapMode
= pOutWin
->GetMapMode();
3730 Point aOrigin
= aOldMapMode
.GetOrigin();
3731 Point aViewPos
= pView
->GetOutputArea().TopLeft();
3732 aOrigin
.Move( aViewPos
.X(), aViewPos
.Y() );
3733 aClipRec
.Move( -aViewPos
.X(), -aViewPos
.Y() );
3734 MapMode
aNewMapMode( aOldMapMode
);
3735 aNewMapMode
.SetOrigin( aOrigin
);
3736 pOutWin
->SetMapMode( aNewMapMode
);
3737 pOutWin
->SetClipRegion( Region( GetTextRanger()->GetPolyPolygon() ) );
3740 pOutWin
->DrawOutDev( aClipRec
.TopLeft(), aClipRec
.GetSize(),
3741 Point(0,0), aClipRec
.GetSize(), *pVDev
);
3743 if ( GetTextRanger() )
3747 pOutWin
->SetClipRegion( aOldRegion
);
3749 pOutWin
->SetClipRegion();
3750 pOutWin
->SetMapMode( aOldMapMode
);
3754 pView
->DrawSelection();
3759 if ( !IsVertical() )
3761 aStartPos
= pView
->GetOutputArea().TopLeft();
3762 aStartPos
.X() -= pView
->GetVisDocLeft();
3763 aStartPos
.Y() -= pView
->GetVisDocTop();
3767 aStartPos
= pView
->GetOutputArea().TopRight();
3768 aStartPos
.X() += pView
->GetVisDocTop();
3769 aStartPos
.Y() -= pView
->GetVisDocLeft();
3772 // Wenn Doc-Breite < OutputArea,Width, nicht umgebrochene Felder,
3773 // stehen die Felder sonst �ber, wenn > Zeile.
3774 // ( Oben nicht, da dort bereits Doc-Breite von Formatierung mit drin )
3775 if ( !IsVertical() && ( pView
->GetOutputArea().GetWidth() > GetPaperSize().Width() ) )
3777 long nMaxX
= pView
->GetOutputArea().Left() + GetPaperSize().Width();
3778 if ( aClipRec
.Left() > nMaxX
)
3780 if ( aClipRec
.Right() > nMaxX
)
3781 aClipRec
.Right() = nMaxX
;
3784 sal_Bool bClipRegion
= pOutWin
->IsClipRegion();
3785 Region aOldRegion
= pOutWin
->GetClipRegion();
3786 pOutWin
->IntersectClipRegion( aClipRec
);
3788 Paint( pOutWin
, aClipRec
, aStartPos
);
3791 pOutWin
->SetClipRegion( aOldRegion
);
3793 pOutWin
->SetClipRegion();
3795 pView
->DrawSelection();
3800 void ImpEditEngine::InsertContent( ContentNode
* pNode
, sal_uInt16 nPos
)
3802 DBG_ASSERT( pNode
, "NULL-Poointer in InsertContent! " );
3803 DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" );
3804 ParaPortion
* pNew
= new ParaPortion( pNode
);
3805 GetParaPortions().Insert( pNew
, nPos
);
3806 aEditDoc
.Insert( pNode
, nPos
);
3807 if ( IsCallParaInsertedOrDeleted() )
3808 GetEditEnginePtr()->ParagraphInserted( nPos
);
3811 EditPaM
ImpEditEngine::SplitContent( sal_uInt16 nNode
, sal_uInt16 nSepPos
)
3813 ContentNode
* pNode
= aEditDoc
.SaveGetObject( nNode
);
3814 DBG_ASSERT( pNode
, "Ungueltiger Node in SplitContent" );
3815 DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" );
3816 DBG_ASSERT( nSepPos
<= pNode
->Len(), "Index im Wald: SplitContent" );
3817 EditPaM
aPaM( pNode
, nSepPos
);
3818 return ImpInsertParaBreak( aPaM
);
3821 EditPaM
ImpEditEngine::ConnectContents( sal_uInt16 nLeftNode
, sal_Bool bBackward
)
3823 ContentNode
* pLeftNode
= aEditDoc
.SaveGetObject( nLeftNode
);
3824 ContentNode
* pRightNode
= aEditDoc
.SaveGetObject( nLeftNode
+1 );
3825 DBG_ASSERT( pLeftNode
, "Ungueltiger linker Node in ConnectContents" );
3826 DBG_ASSERT( pRightNode
, "Ungueltiger rechter Node in ConnectContents" );
3827 DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" );
3828 return ImpConnectParagraphs( pLeftNode
, pRightNode
, bBackward
);
3831 void ImpEditEngine::SetUpdateMode( sal_Bool bUp
, EditView
* pCurView
, sal_Bool bForceUpdate
)
3833 sal_Bool bChanged
= ( GetUpdateMode() != bUp
);
3835 // Beim Umschalten von sal_True auf sal_False waren alle Selektionen sichtbar,
3837 // Umgekehrt waren alle unsichtbar => malen
3839 // DrawAllSelections(); sieht im Outliner schlecht aus !
3840 // EditView* pView = aEditViewList.First();
3843 // DBG_CHKOBJ( pView, EditView, 0 );
3844 // pView->pImpEditView->DrawSelection();
3845 // pView = aEditViewList.Next();
3848 // Wenn !bFormatted, also z.B. nach SetText, braucht bei UpdateMode sal_True
3849 // nicht sofort formatiert werden, weil warscheinlich noch Text kommt.
3850 // Spaetestens bei einem Paint / CalcTextWidth wird formatiert.
3853 if ( bUpdate
&& ( bChanged
|| bForceUpdate
) )
3854 FormatAndUpdate( pCurView
);
3857 void ImpEditEngine::ShowParagraph( sal_uInt16 nParagraph
, sal_Bool bShow
)
3859 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3860 DBG_ASSERT( pPPortion
, "ShowParagraph: Absatz existiert nicht!" );
3861 if ( pPPortion
&& ( pPPortion
->IsVisible() != bShow
) )
3863 pPPortion
->SetVisible( bShow
);
3867 // Als deleted kenzeichnen, damit keine Selektion auf diesem
3868 // Absatz beginnt oder endet...
3869 DeletedNodeInfo
* pDelInfo
= new DeletedNodeInfo( (sal_uIntPtr
)pPPortion
->GetNode(), nParagraph
);
3870 aDeletedNodes
.Insert( pDelInfo
, aDeletedNodes
.Count() );
3872 // Dann kriege ich den unteren Bereich nicht invalidiert,
3873 // wenn UpdateMode = sal_False!
3874 // Wenn doch, dann vor SetVisible auf sal_False merken!
3875 // nCurTextHeight -= pPPortion->GetHeight();
3878 if ( bShow
&& ( pPPortion
->IsInvalid() || !pPPortion
->nHeight
) )
3880 if ( !GetTextRanger() )
3882 if ( pPPortion
->IsInvalid() )
3884 Font
aOldFont( GetRefDevice()->GetFont() );
3885 CreateLines( nParagraph
, 0 ); // 0: Kein TextRanger
3886 if ( aStatus
.DoRestoreFont() )
3887 GetRefDevice()->SetFont( aOldFont
);
3891 CalcHeight( pPPortion
);
3893 nCurTextHeight
+= pPPortion
->GetHeight();
3897 nCurTextHeight
= 0x7fffffff;
3901 pPPortion
->SetMustRepaint( sal_True
);
3902 if ( GetUpdateMode() && !IsInUndo() && !GetTextRanger() )
3904 aInvalidRec
= Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion
) ),
3905 Point( GetPaperSize().Width(), nCurTextHeight
) );
3906 UpdateViews( GetActiveView() );
3911 sal_Bool
ImpEditEngine::IsParagraphVisible( sal_uInt16 nParagraph
)
3913 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3914 DBG_ASSERT( pPPortion
, "IsParagraphVisible: Absatz existiert nicht!" );
3916 return pPPortion
->IsVisible();
3920 EditSelection
ImpEditEngine::MoveParagraphs( Range aOldPositions
, sal_uInt16 nNewPos
, EditView
* pCurView
)
3922 DBG_ASSERT( GetParaPortions().Count() != 0, "Keine Absaetze gefunden: MoveParagraphs" );
3923 if ( GetParaPortions().Count() == 0 )
3924 return EditSelection();
3925 aOldPositions
.Justify();
3927 EditSelection
aSel( ImpMoveParagraphs( aOldPositions
, nNewPos
) );
3929 if ( nNewPos
>= GetParaPortions().Count() )
3930 nNewPos
= GetParaPortions().Count() - 1;
3932 // Dort, wo der Absatz eingefuegt wurde, muss richtig gepainted werden:
3933 // Dort, wo der Absatz entfernt wurde, muss richtig gepainted werden:
3934 // ( Und dazwischen entsprechend auch...)
3935 if ( pCurView
&& ( GetUpdateMode() == sal_True
) )
3937 // in diesem Fall kann ich direkt neu malen, ohne die
3938 // Portions zu Invalidieren.
3939 sal_uInt16 nFirstPortion
= Min( (sal_uInt16
)aOldPositions
.Min(), nNewPos
);
3940 sal_uInt16 nLastPortion
= Max( (sal_uInt16
)aOldPositions
.Max(), nNewPos
);
3942 ParaPortion
* pUpperPortion
= GetParaPortions().SaveGetObject( nFirstPortion
);
3943 ParaPortion
* pLowerPortion
= GetParaPortions().SaveGetObject( nLastPortion
);
3945 aInvalidRec
= Rectangle(); // leermachen
3946 aInvalidRec
.Left() = 0;
3947 aInvalidRec
.Right() = aPaperSize
.Width();
3948 aInvalidRec
.Top() = GetParaPortions().GetYOffset( pUpperPortion
);
3949 aInvalidRec
.Bottom() = GetParaPortions().GetYOffset( pLowerPortion
) + pLowerPortion
->GetHeight();
3951 UpdateViews( pCurView
);
3955 // aber der oberen ungueltigen Position neu painten...
3956 sal_uInt16 nFirstInvPara
= Min( (sal_uInt16
)aOldPositions
.Min(), nNewPos
);
3957 InvalidateFromParagraph( nFirstInvPara
);
3962 void ImpEditEngine::InvalidateFromParagraph( sal_uInt16 nFirstInvPara
)
3964 // Es werden nicht die folgenden Absaetze invalidiert,
3965 // da ResetHeight() => Groessenanderung => alles folgende wird
3966 // sowieso neu ausgegeben.
3967 ParaPortion
* pTmpPortion
;
3968 if ( nFirstInvPara
!= 0 )
3970 pTmpPortion
= GetParaPortions().GetObject( nFirstInvPara
-1 );
3971 pTmpPortion
->MarkInvalid( pTmpPortion
->GetNode()->Len(), 0 );
3975 pTmpPortion
= GetParaPortions().GetObject( 0 );
3976 pTmpPortion
->MarkSelectionInvalid( 0, pTmpPortion
->GetNode()->Len() );
3978 pTmpPortion
->ResetHeight();
3981 IMPL_LINK_INLINE_START( ImpEditEngine
, StatusTimerHdl
, Timer
*, EMPTYARG
)
3986 IMPL_LINK_INLINE_END( ImpEditEngine
, StatusTimerHdl
, Timer
*, EMPTYARG
)
3988 void ImpEditEngine::CallStatusHdl()
3990 if ( aStatusHdlLink
.IsSet() && aStatus
.GetStatusWord() )
3992 // Der Status muss vor Call zurueckgesetzt werden,
3993 // da im Hdl evtl. weitere Fags gesetzt werden...
3994 EditStatus
aTmpStatus( aStatus
);
3996 aStatusHdlLink
.Call( &aTmpStatus
);
3997 aStatusTimer
.Stop(); // Falls von Hand gerufen...
4001 ContentNode
* ImpEditEngine::GetPrevVisNode( ContentNode
* pCurNode
)
4003 ParaPortion
* pPortion
= FindParaPortion( pCurNode
);
4004 DBG_ASSERT( pPortion
, "GetPrevVisibleNode: Keine passende Portion!" );
4005 pPortion
= GetPrevVisPortion( pPortion
);
4007 return pPortion
->GetNode();
4011 ContentNode
* ImpEditEngine::GetNextVisNode( ContentNode
* pCurNode
)
4013 ParaPortion
* pPortion
= FindParaPortion( pCurNode
);
4014 DBG_ASSERT( pPortion
, "GetNextVisibleNode: Keine passende Portion!" );
4015 pPortion
= GetNextVisPortion( pPortion
);
4017 return pPortion
->GetNode();
4021 ParaPortion
* ImpEditEngine::GetPrevVisPortion( ParaPortion
* pCurPortion
)
4023 sal_uInt16 nPara
= GetParaPortions().GetPos( pCurPortion
);
4024 DBG_ASSERT( nPara
< GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisPortion" );
4025 ParaPortion
* pPortion
= nPara
? GetParaPortions()[--nPara
] : 0;
4026 while ( pPortion
&& !pPortion
->IsVisible() )
4027 pPortion
= nPara
? GetParaPortions()[--nPara
] : 0;
4032 ParaPortion
* ImpEditEngine::GetNextVisPortion( ParaPortion
* pCurPortion
)
4034 sal_uInt16 nPara
= GetParaPortions().GetPos( pCurPortion
);
4035 DBG_ASSERT( nPara
< GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisNode" );
4036 ParaPortion
* pPortion
= GetParaPortions().SaveGetObject( ++nPara
);
4037 while ( pPortion
&& !pPortion
->IsVisible() )
4038 pPortion
= GetParaPortions().SaveGetObject( ++nPara
);
4043 EditPaM
ImpEditEngine::InsertParagraph( sal_uInt16 nPara
)
4048 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
-1 );
4050 pNode
= GetEditDoc().SaveGetObject( GetEditDoc().Count() - 1 );
4051 DBG_ASSERT( pNode
, "Kein einziger Absatz in InsertParagraph ?" );
4052 aPaM
= EditPaM( pNode
, pNode
->Len() );
4056 ContentNode
* pNode
= GetEditDoc().SaveGetObject( 0 );
4057 aPaM
= EditPaM( pNode
, 0 );
4060 return ImpInsertParaBreak( aPaM
);
4063 EditSelection
* ImpEditEngine::SelectParagraph( sal_uInt16 nPara
)
4065 EditSelection
* pSel
= 0;
4066 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
);
4067 DBG_ASSERTWARNING( pNode
, "Absatz existiert nicht: SelectParagraph" );
4069 pSel
= new EditSelection( EditPaM( pNode
, 0 ), EditPaM( pNode
, pNode
->Len() ) );
4074 void ImpEditEngine::FormatAndUpdate( EditView
* pCurView
)
4080 IdleFormatAndUpdate( pCurView
);
4084 UpdateViews( pCurView
);
4088 void ImpEditEngine::SetFlatMode( sal_Bool bFlat
)
4090 if ( bFlat
!= aStatus
.UseCharAttribs() )
4094 aStatus
.TurnOnFlags( EE_CNTRL_USECHARATTRIBS
);
4096 aStatus
.TurnOffFlags( EE_CNTRL_USECHARATTRIBS
);
4098 aEditDoc
.CreateDefFont( !bFlat
);
4101 UpdateViews( (EditView
*) 0);
4103 pActiveView
->ShowCursor();
4106 void ImpEditEngine::SetCharStretching( sal_uInt16 nX
, sal_uInt16 nY
)
4108 bool bChanged(false);
4109 if ( !IsVertical() )
4111 bChanged
= nStretchX
!=nX
|| nStretchY
!=nY
;
4117 bChanged
= nStretchX
!=nY
|| nStretchY
!=nX
;
4122 if (bChanged
&& aStatus
.DoStretch())
4125 // (potentially) need everything redrawn
4126 aInvalidRec
=Rectangle(0,0,1000000,1000000);
4127 UpdateViews( GetActiveView() );
4131 void ImpEditEngine::DoStretchChars( sal_uInt16 nX
, sal_uInt16 nY
)
4133 UndoActionStart( EDITUNDO_STRETCH
);
4134 sal_uInt16 nParas
= GetEditDoc().Count();
4135 for ( sal_uInt16 nPara
= 0; nPara
< nParas
; nPara
++ )
4137 ContentNode
* pNode
= GetEditDoc()[nPara
];
4138 SfxItemSet
aTmpSet( pNode
->GetContentAttribs().GetItems() );
4143 SvxCharScaleWidthItem
* pNewWidth
= (SvxCharScaleWidthItem
*) pNode
->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH
).Clone();
4144 sal_uInt32 nProp
= pNewWidth
->GetValue(); // sal_uInt32, kann temporaer gross werden
4147 pNewWidth
->SetValue( (sal_uInt16
)nProp
);
4148 aTmpSet
.Put( *pNewWidth
);
4152 const SvxKerningItem
& rKerningItem
=
4153 (const SvxKerningItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_KERNING
);
4154 SvxKerningItem
* pNewKerning
= (SvxKerningItem
*)rKerningItem
.Clone();
4155 long nKerning
= pNewKerning
->GetValue();
4161 else if ( nKerning
< 0 )
4163 // Bei Negativen Werten:
4164 // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt.
4168 pNewKerning
->SetValue( (short)nKerning
);
4169 aTmpSet
.Put( *pNewKerning
);
4173 aTmpSet
.ClearItem( EE_CHAR_FONTWIDTH
);
4178 for ( int nItem
= 0; nItem
< 3; nItem
++ )
4180 USHORT nItemId
= EE_CHAR_FONTHEIGHT
;
4182 nItemId
= EE_CHAR_FONTHEIGHT_CJK
;
4183 else if ( nItem
== 2 )
4184 nItemId
= EE_CHAR_FONTHEIGHT_CTL
;
4186 const SvxFontHeightItem
& rHeightItem
=
4187 (const SvxFontHeightItem
&)pNode
->GetContentAttribs().GetItem( nItemId
);
4188 SvxFontHeightItem
* pNewHeight
= (SvxFontHeightItem
*)rHeightItem
.Clone();
4189 sal_uInt32 nHeight
= pNewHeight
->GetHeight();
4192 pNewHeight
->SetHeightValue( nHeight
);
4193 aTmpSet
.Put( *pNewHeight
);
4198 const SvxULSpaceItem
& rULSpaceItem
=
4199 (const SvxULSpaceItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
4200 SvxULSpaceItem
* pNewUL
= (SvxULSpaceItem
*)rULSpaceItem
.Clone();
4201 sal_uInt32 nUpper
= pNewUL
->GetUpper();
4204 pNewUL
->SetUpper( (sal_uInt16
)nUpper
);
4205 sal_uInt32 nLower
= pNewUL
->GetLower();
4208 pNewUL
->SetLower( (sal_uInt16
)nLower
);
4209 aTmpSet
.Put( *pNewUL
);
4213 aTmpSet
.ClearItem( EE_CHAR_FONTHEIGHT
);
4215 SetParaAttribs( nPara
, aTmpSet
);
4218 sal_uInt16 nLastEnd
= 0; // damit nach entfernen und neu nicht nochmal
4219 CharAttribArray
& rAttribs
= pNode
->GetCharAttribs().GetAttribs();
4220 sal_uInt16 nAttribs
= rAttribs
.Count();
4221 for ( sal_uInt16 nAttr
= 0; nAttr
< nAttribs
; nAttr
++ )
4223 EditCharAttrib
* pAttr
= rAttribs
[nAttr
];
4224 if ( pAttr
->GetStart() >= nLastEnd
)
4226 sal_uInt16 nWhich
= pAttr
->Which();
4227 SfxPoolItem
* pNew
= 0;
4228 if ( nWhich
== EE_CHAR_FONTHEIGHT
)
4230 SvxFontHeightItem
* pNewHeight
= (SvxFontHeightItem
*)pAttr
->GetItem()->Clone();
4231 sal_uInt32 nHeight
= pNewHeight
->GetHeight();
4234 pNewHeight
->SetHeightValue( nHeight
);
4237 else if ( nWhich
== EE_CHAR_FONTWIDTH
)
4239 SvxCharScaleWidthItem
* pNewWidth
= (SvxCharScaleWidthItem
*)pAttr
->GetItem()->Clone();
4240 sal_uInt32 nProp
= pNewWidth
->GetValue();
4243 pNewWidth
->SetValue( (sal_uInt16
)nProp
);
4246 else if ( nWhich
== EE_CHAR_KERNING
)
4248 SvxKerningItem
* pNewKerning
= (SvxKerningItem
*)pAttr
->GetItem()->Clone();
4249 long nKerning
= pNewKerning
->GetValue();
4255 else if ( nKerning
< 0 )
4257 // Bei Negativen Werten:
4258 // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt.
4262 pNewKerning
->SetValue( (short)nKerning
);
4267 SfxItemSet
_aTmpSet( GetEmptyItemSet() );
4268 _aTmpSet
.Put( *pNew
);
4269 SetAttribs( EditSelection( EditPaM( pNode
, pAttr
->GetStart() ),
4270 EditPaM( pNode
, pAttr
->GetEnd() ) ), _aTmpSet
);
4272 nLastEnd
= pAttr
->GetEnd();
4278 UndoActionEnd( EDITUNDO_STRETCH
);
4281 const SvxNumberFormat
* ImpEditEngine::GetNumberFormat( const ContentNode
*pNode
) const
4283 const SvxNumberFormat
*pRes
= 0;
4287 // get index of paragraph
4288 USHORT nPara
= GetEditDoc().GetPos( const_cast< ContentNode
* >(pNode
) );
4289 DBG_ASSERT( nPara
< USHRT_MAX
, "node not found in array" );
4290 if (nPara
< USHRT_MAX
)
4292 // the called function may be overloaded by an OutlinerEditEng object to provide
4293 // access to the SvxNumberFormat of the Outliner.
4294 // The EditEngine implementation will just return 0.
4295 pRes
= pEditEngine
->GetNumberFormat( nPara
);
4302 sal_Int32
ImpEditEngine::GetSpaceBeforeAndMinLabelWidth(
4303 const ContentNode
*pNode
,
4304 sal_Int32
*pnSpaceBefore
, sal_Int32
*pnMinLabelWidth
) const
4306 // nSpaceBefore matches the ODF attribut text:space-before
4307 // nMinLabelWidth matches the ODF attribut text:min-label-width
4309 const SvxNumberFormat
*pNumFmt
= GetNumberFormat( pNode
);
4311 // if no number format was found we have no Outliner or the numbering level
4312 // within the Outliner is -1 which means no number format should be applied.
4313 // Thus the default values to be returned are 0.
4314 sal_Int32 nSpaceBefore
= 0;
4315 sal_Int32 nMinLabelWidth
= 0;
4319 nMinLabelWidth
= -pNumFmt
->GetFirstLineOffset();
4320 nSpaceBefore
= pNumFmt
->GetAbsLSpace() - nMinLabelWidth
;
4321 DBG_ASSERT( nMinLabelWidth
>= 0, "ImpEditEngine::GetSpaceBeforeAndMinLabelWidth: min-label-width < 0 encountered" );
4324 *pnSpaceBefore
= nSpaceBefore
;
4325 if (pnMinLabelWidth
)
4326 *pnMinLabelWidth
= nMinLabelWidth
;
4328 return nSpaceBefore
+ nMinLabelWidth
;
4331 const SvxLRSpaceItem
& ImpEditEngine::GetLRSpaceItem( ContentNode
* pNode
)
4333 return (const SvxLRSpaceItem
&)pNode
->GetContentAttribs().GetItem( aStatus
.IsOutliner() ? EE_PARA_OUTLLRSPACE
: EE_PARA_LRSPACE
);
4336 // Either sets the digit mode at the output device or
4337 // modifies the passed string according to the text numeral setting:
4338 void ImpEditEngine::ImplInitDigitMode( OutputDevice
* pOutDev
, String
* pString
, xub_StrLen nStt
, xub_StrLen nLen
, LanguageType eCurLang
)
4340 // #114278# Also setting up digit language from Svt options
4341 // (cannot reliably inherit the outdev's setting)
4343 pCTLOptions
= new SvtCTLOptions
;
4345 LanguageType eLang
= eCurLang
;
4346 const SvtCTLOptions::TextNumerals nCTLTextNumerals
= pCTLOptions
->GetCTLTextNumerals();
4348 if ( SvtCTLOptions::NUMERALS_HINDI
== nCTLTextNumerals
)
4349 eLang
= LANGUAGE_ARABIC_SAUDI_ARABIA
;
4350 else if ( SvtCTLOptions::NUMERALS_ARABIC
== nCTLTextNumerals
)
4351 eLang
= LANGUAGE_ENGLISH
;
4352 else if ( SvtCTLOptions::NUMERALS_SYSTEM
== nCTLTextNumerals
)
4353 eLang
= (LanguageType
) Application::GetSettings().GetLanguage();
4357 pOutDev
->SetDigitLanguage( eLang
);
4361 // see sallayout.cxx in vcl
4363 switch( eLang
& LANGUAGE_MASK_PRIMARY
)
4368 case LANGUAGE_ARABIC_SAUDI_ARABIA
& LANGUAGE_MASK_PRIMARY
:
4369 nOffset
= 0x0660 - '0'; // arabic-indic digits
4371 case LANGUAGE_URDU
& LANGUAGE_MASK_PRIMARY
:
4372 case LANGUAGE_PUNJABI
& LANGUAGE_MASK_PRIMARY
: //???
4373 case LANGUAGE_SINDHI
& LANGUAGE_MASK_PRIMARY
:
4374 nOffset
= 0x06F0 - '0'; // eastern arabic-indic digits
4379 const xub_StrLen nEnd
= nStt
+ nLen
;
4380 for( xub_StrLen nIdx
= nStt
; nIdx
< nEnd
; ++nIdx
)
4382 sal_Unicode nChar
= pString
->GetChar( nIdx
);
4383 if( (nChar
< '0') || ('9' < nChar
) )
4385 nChar
= (sal_Unicode
)(nChar
+ nOffset
);
4386 pString
->SetChar( nIdx
, nChar
);
4392 void ImpEditEngine::ImplInitLayoutMode( OutputDevice
* pOutDev
, USHORT nPara
, USHORT nIndex
)
4396 if ( nIndex
== 0xFFFF )
4398 bCTL
= HasScriptType( nPara
, i18n::ScriptType::COMPLEX
);
4399 bR2L
= IsRightToLeft( nPara
);
4403 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
);
4404 short nScriptType
= GetScriptType( EditPaM( pNode
, nIndex
+1 ) );
4405 bCTL
= nScriptType
== i18n::ScriptType::COMPLEX
;
4406 bR2L
= GetRightToLeft( nPara
, nIndex
+ 1); // this change was discussed in issue 37190
4407 // it also works for issue 55927
4410 ULONG nLayoutMode
= pOutDev
->GetLayoutMode();
4412 // We always use the left postion for DrawText()
4413 nLayoutMode
&= ~(TEXT_LAYOUT_BIDI_RTL
);
4415 if ( !bCTL
&& !bR2L
)
4417 // No CTL/Bidi checking neccessary
4418 nLayoutMode
|= ( TEXT_LAYOUT_COMPLEX_DISABLED
| TEXT_LAYOUT_BIDI_STRONG
);
4422 // CTL/Bidi checking neccessary
4423 // Don't use BIDI_STRONG, VCL must do some checks.
4424 nLayoutMode
&= ~( TEXT_LAYOUT_COMPLEX_DISABLED
| TEXT_LAYOUT_BIDI_STRONG
);
4427 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
|TEXT_LAYOUT_TEXTORIGIN_LEFT
;
4430 pOutDev
->SetLayoutMode( nLayoutMode
);
4432 // #114278# Also setting up digit language from Svt options
4433 // (cannot reliably inherit the outdev's setting)
4437 pCTLOptions
= new SvtCTLOptions
;
4439 if ( SvtCTLOptions::NUMERALS_HINDI
== pCTLOptions
->GetCTLTextNumerals() )
4440 eLang
= LANGUAGE_ARABIC_SAUDI_ARABIA
;
4441 else if ( SvtCTLOptions::NUMERALS_ARABIC
== pCTLOptions
->GetCTLTextNumerals() )
4442 eLang
= LANGUAGE_ENGLISH
;
4444 eLang
= (LanguageType
) Application::GetSettings().GetLanguage();
4446 pOutDev
->SetDigitLanguage( eLang
);
4449 Reference
< i18n::XBreakIterator
> ImpEditEngine::ImplGetBreakIterator() const
4453 Reference
< lang::XMultiServiceFactory
> xMSF( ::comphelper::getProcessServiceFactory() );
4454 xBI
.set( xMSF
->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY
);
4459 Reference
< i18n::XExtendedInputSequenceChecker
> ImpEditEngine::ImplGetInputSequenceChecker() const
4463 Reference
< lang::XMultiServiceFactory
> xMSF
= ::comphelper::getProcessServiceFactory();
4464 Reference
< XInterface
> xI
= xMSF
->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) );
4467 Any x
= xI
->queryInterface( ::getCppuType((const Reference
< i18n::XExtendedInputSequenceChecker
>*)0) );
4474 Color
ImpEditEngine::GetAutoColor() const
4476 Color aColor
= const_cast<ImpEditEngine
*>(this)->GetColorConfig().GetColorValue( svtools::FONTCOLOR
).nColor
;
4478 if ( GetBackgroundColor() != COL_AUTO
)
4480 if ( GetBackgroundColor().IsDark() && aColor
.IsDark() )
4482 else if ( GetBackgroundColor().IsBright() && aColor
.IsBright() )
4490 BOOL
ImpEditEngine::ImplCalcAsianCompression( ContentNode
* pNode
, TextPortion
* pTextPortion
, USHORT nStartPos
, sal_Int32
* pDXArray
, USHORT n100thPercentFromMax
, BOOL bManipulateDXArray
)
4492 DBG_ASSERT( GetAsianCompressionMode(), "ImplCalcAsianCompression - Why?" );
4493 DBG_ASSERT( pTextPortion
->GetLen(), "ImplCalcAsianCompression - Empty Portion?" );
4495 // Percent is 1/100 Percent...
4497 if ( n100thPercentFromMax
== 10000 )
4498 pTextPortion
->SetExtraInfos( NULL
);
4500 BOOL bCompressed
= FALSE
;
4502 if ( GetScriptType( EditPaM( pNode
, nStartPos
+1 ) ) == i18n::ScriptType::ASIAN
)
4504 long nNewPortionWidth
= pTextPortion
->GetSize().Width();
4505 USHORT nPortionLen
= pTextPortion
->GetLen();
4506 for ( USHORT n
= 0; n
< nPortionLen
; n
++ )
4508 BYTE nType
= GetCharTypeForCompression( pNode
->GetChar( n
+nStartPos
) );
4510 BOOL bCompressPunctuation
= ( nType
== CHAR_PUNCTUATIONLEFT
) || ( nType
== CHAR_PUNCTUATIONRIGHT
);
4511 BOOL bCompressKana
= ( nType
== CHAR_KANA
) && ( GetAsianCompressionMode() == text::CharacterCompressionType::PUNCTUATION_AND_KANA
);
4513 // create Extra infos only if needed...
4514 if ( bCompressPunctuation
|| bCompressKana
)
4516 if ( !pTextPortion
->GetExtraInfos() )
4518 ExtraPortionInfo
* pExtraInfos
= new ExtraPortionInfo
;
4519 pTextPortion
->SetExtraInfos( pExtraInfos
);
4520 pExtraInfos
->nOrgWidth
= pTextPortion
->GetSize().Width();
4521 pExtraInfos
->nAsianCompressionTypes
= CHAR_NORMAL
;
4523 pTextPortion
->GetExtraInfos()->nMaxCompression100thPercent
= n100thPercentFromMax
;
4524 pTextPortion
->GetExtraInfos()->nAsianCompressionTypes
|= nType
;
4525 // pTextPortion->GetExtraInfos()->nCompressedChars++;
4528 if ( (n
+1) < nPortionLen
)
4530 nOldCharWidth
= pDXArray
[n
];
4534 if ( bManipulateDXArray
)
4535 nOldCharWidth
= nNewPortionWidth
- pTextPortion
->GetExtraInfos()->nPortionOffsetX
;
4537 nOldCharWidth
= pTextPortion
->GetExtraInfos()->nOrgWidth
;
4539 nOldCharWidth
-= ( n
? pDXArray
[n
-1] : 0 );
4543 if ( bCompressPunctuation
)
4545 // pTextPortion->GetExtraInfos()->nComressionWeight += 5;
4546 nCompress
= nOldCharWidth
/ 2;
4550 // pTextPortion->GetExtraInfos()->nComressionWeight += 1;
4551 nCompress
= nOldCharWidth
/ 10;
4554 if ( n100thPercentFromMax
!= 10000 )
4556 nCompress
*= n100thPercentFromMax
;
4563 nNewPortionWidth
-= nCompress
;
4564 pTextPortion
->GetExtraInfos()->bCompressed
= TRUE
;
4567 // Special handling for rightpunctuation: For the 'compression' we must
4568 // start th eoutput before the normal char position....
4569 if ( bManipulateDXArray
&& ( pTextPortion
->GetLen() > 1 ) )
4571 if ( !pTextPortion
->GetExtraInfos()->pOrgDXArray
)
4572 pTextPortion
->GetExtraInfos()->SaveOrgDXArray( pDXArray
, pTextPortion
->GetLen()-1 );
4574 if ( nType
== CHAR_PUNCTUATIONRIGHT
)
4576 // If it's the first char, I must handle it in Paint()...
4579 // -1: No entry for the last character
4580 for ( USHORT i
= n
-1; i
< (nPortionLen
-1); i
++ )
4581 pDXArray
[i
] -= nCompress
;
4585 pTextPortion
->GetExtraInfos()->bFirstCharIsRightPunktuation
= TRUE
;
4586 pTextPortion
->GetExtraInfos()->nPortionOffsetX
= -nCompress
;
4591 // -1: No entry for the last character
4592 for ( USHORT i
= n
; i
< (nPortionLen
-1); i
++ )
4593 pDXArray
[i
] -= nCompress
;
4600 if ( bCompressed
&& ( n100thPercentFromMax
== 10000 ) )
4601 pTextPortion
->GetExtraInfos()->nWidthFullCompression
= nNewPortionWidth
;
4603 pTextPortion
->GetSize().Width() = nNewPortionWidth
;
4605 if ( pTextPortion
->GetExtraInfos() && ( n100thPercentFromMax
!= 10000 ) )
4607 // Maybe rounding errors in nNewPortionWidth, assure that width not bigger than expected
4608 long nShrink
= pTextPortion
->GetExtraInfos()->nOrgWidth
- pTextPortion
->GetExtraInfos()->nWidthFullCompression
;
4609 nShrink
*= n100thPercentFromMax
;
4611 long nNewWidth
= pTextPortion
->GetExtraInfos()->nOrgWidth
- nShrink
;
4612 if ( nNewWidth
< pTextPortion
->GetSize().Width() )
4613 pTextPortion
->GetSize().Width() = nNewWidth
;
4620 void ImpEditEngine::ImplExpandCompressedPortions( EditLine
* pLine
, ParaPortion
* pParaPortion
, long nRemainingWidth
)
4622 BOOL bFoundCompressedPortion
= FALSE
;
4623 long nCompressed
= 0;
4624 // long nCompressWeight = 0;
4625 TextPortionList aCompressedPortions
;
4627 USHORT nPortion
= pLine
->GetEndPortion();
4628 TextPortion
* pTP
= pParaPortion
->GetTextPortions()[ nPortion
];
4629 while ( pTP
&& ( pTP
->GetKind() == PORTIONKIND_TEXT
) )
4631 if ( pTP
->GetExtraInfos() && pTP
->GetExtraInfos()->bCompressed
)
4633 bFoundCompressedPortion
= TRUE
;
4634 nCompressed
+= pTP
->GetExtraInfos()->nOrgWidth
- pTP
->GetSize().Width();
4635 aCompressedPortions
.Insert( pTP
, aCompressedPortions
.Count() );
4637 pTP
= ( nPortion
> pLine
->GetStartPortion() ) ? pParaPortion
->GetTextPortions()[ --nPortion
] : NULL
;
4640 if ( bFoundCompressedPortion
)
4642 long nCompressPercent
= 0;
4643 if ( nCompressed
> nRemainingWidth
)
4645 nCompressPercent
= nCompressed
- nRemainingWidth
;
4646 DBG_ASSERT( nCompressPercent
< 200000, "ImplExpandCompressedPortions - Overflow!" );
4647 nCompressPercent
*= 10000;
4648 nCompressPercent
/= nCompressed
;
4651 for ( USHORT n
= 0; n
< aCompressedPortions
.Count(); n
++ )
4653 pTP
= aCompressedPortions
[n
];
4654 pTP
->GetExtraInfos()->bCompressed
= FALSE
;
4655 pTP
->GetSize().Width() = pTP
->GetExtraInfos()->nOrgWidth
;
4656 if ( nCompressPercent
)
4658 USHORT nTxtPortion
= pParaPortion
->GetTextPortions().GetPos( pTP
);
4659 USHORT nTxtPortionStart
= pParaPortion
->GetTextPortions().GetStartPos( nTxtPortion
);
4660 DBG_ASSERT( nTxtPortionStart
>= pLine
->GetStart(), "Portion doesn't belong to the line!!!" );
4661 sal_Int32
* pDXArray
= const_cast< sal_Int32
* >( pLine
->GetCharPosArray().GetData()+( nTxtPortionStart
-pLine
->GetStart() ) );
4662 if ( pTP
->GetExtraInfos()->pOrgDXArray
)
4663 memcpy( pDXArray
, pTP
->GetExtraInfos()->pOrgDXArray
, (pTP
->GetLen()-1)*sizeof(sal_Int32
) );
4664 ImplCalcAsianCompression( pParaPortion
->GetNode(), pTP
, nTxtPortionStart
, pDXArray
, (USHORT
)nCompressPercent
, TRUE
);
4669 aCompressedPortions
.Remove( 0, aCompressedPortions
.Count() );
4672 // redesigned to work with TextMarkingVector
4673 void ImpEditEngine::ImplFillTextMarkingVector(const lang::Locale
& rLocale
, EEngineData::TextMarkingVector
& rTextMarkingVector
, const String
& rTxt
, const USHORT nIdx
, const USHORT nLen
) const
4675 // determine relevant logical text elements for the just-rendered
4676 // string of characters.
4677 Reference
< i18n::XBreakIterator
> _xBI(ImplGetBreakIterator());
4682 sal_Int32
nNextCellBreak(_xBI
->nextCharacters(rTxt
, nIdx
, rLocale
, i18n::CharacterIteratorMode::SKIPCELL
, 0, nDone
));
4683 i18n::Boundary
nNextWordBoundary(_xBI
->getWordBoundary(rTxt
, nIdx
, rLocale
, i18n::WordType::ANY_WORD
, sal_True
));
4684 sal_Int32
nNextSentenceBreak(_xBI
->endOfSentence(rTxt
, nIdx
, rLocale
));
4686 const sal_Int32
nEndPos(nIdx
+ nLen
);
4689 for(i
= nIdx
; i
< nEndPos
; i
++)
4691 // create the entries for the respective break positions
4692 if(i
== nNextCellBreak
)
4694 rTextMarkingVector
.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfCaracter
, i
- nIdx
));
4695 nNextCellBreak
= _xBI
->nextCharacters(rTxt
, i
, rLocale
, i18n::CharacterIteratorMode::SKIPCELL
, 1, nDone
);
4697 if(i
== nNextWordBoundary
.endPos
)
4699 rTextMarkingVector
.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfWord
, i
- nIdx
));
4700 nNextWordBoundary
= _xBI
->getWordBoundary(rTxt
, i
+ 1, rLocale
, i18n::WordType::ANY_WORD
, sal_True
);
4702 if(i
== nNextSentenceBreak
)
4704 rTextMarkingVector
.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfSentence
, i
- nIdx
));
4705 nNextSentenceBreak
= _xBI
->endOfSentence(rTxt
, i
+ 1, rLocale
);