1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #ifndef _OUTDEV_HXX //autogen
29 #include <vcl/outdev.hxx>
30 #endif
31 #ifndef _PRINT_HXX //autogen
32 #include <vcl/print.hxx>
33 #endif
34 #include <vcl/lineinfo.hxx>
35 #ifndef _METRIC_HXX //autogen
36 #include <vcl/metric.hxx>
37 #endif
38 #include <vcl/window.hxx>
39 #include <vcl/svapp.hxx>
40 #ifndef _COM_SUN_STAR_I18N_CHARACTERITERATORMODE_HDL_
41 #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
42 #endif
43 #ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
44 #include <com/sun/star/i18n/WordType.hdl>
45 #endif
46 #include <breakit.hxx>
47 #include <viewsh.hxx> // Bildschirmabgleich
48 #include <viewopt.hxx> // Bildschirmabgleich abschalten, ViewOption
49 #include <fntcache.hxx>
50 #include <IDocumentSettingAccess.hxx>
51 #include <swfont.hxx> // CH_BLANK + CH_BULLET
52 #include <wrong.hxx>
53 #include "dbg_lay.hxx"
54 #include <txtfrm.hxx> // SwTxtFrm
55 #include <pagefrm.hxx>
56 #include <pagedesc.hxx> // SwPageDesc
57 #include <tgrditem.hxx>
58 #include <scriptinfo.hxx>
59 #include <editeng/brshitem.hxx>
60 #include <tools/shl.hxx>
61 #include <swmodule.hxx>
62 #include <accessibilityoptions.hxx>
63 #include <svtools/accessibilityoptions.hxx>
64 #include <doc.hxx>
65 #include <editeng/fhgtitem.hxx>
66 #include <docsh.hxx>
67 #ifndef _POOLFMT_HRC
68 #include <poolfmt.hrc>
69 #endif
70
71 using namespace ::com::sun::star;
72
73 // globale Variablen, werden in FntCache.Hxx bekanntgegeben
74 // Der FontCache wird in TxtInit.Cxx _TXTINIT erzeugt und in _TXTEXIT geloescht
75 SwFntCache *pFntCache = NULL;
76 // Letzter Font, der durch ChgFntCache eingestellt wurde.
77 SwFntObj *pLastFont = NULL;
78 // Die "MagicNumber", die den Fonts zur Identifizierung verpasst wird
79 sal_uInt8* pMagicNo = NULL;
80
81 Color *pWaveCol = 0;
82
83 long SwFntObj::nPixWidth;
84 MapMode* SwFntObj::pPixMap = NULL;
85 OutputDevice* SwFntObj::pPixOut = NULL;
86
87 extern sal_uInt16 UnMapDirection( sal_uInt16 nDir, const sal_Bool bVertFormat );
GetDefaultFontHeight(SwDrawTextInfo & rInf)88 sal_uInt16 GetDefaultFontHeight( SwDrawTextInfo &rInf )
89 {
90 SwDocShell* pDocShell = rInf.GetShell()->GetDoc()->GetDocShell();
91 SfxStyleSheetBasePool* pBasePool = pDocShell->GetStyleSheetPool();
92
93 String aString(SW_RES(STR_POOLCOLL_STANDARD));
94
95 SfxStyleSheetBase* pStyle = pBasePool->Find( aString, (SfxStyleFamily)SFX_STYLE_FAMILY_PARA );
96 SfxItemSet& aTmpSet = pStyle->GetItemSet();
97 SvxFontHeightItem &aDefaultFontItem = (SvxFontHeightItem&)aTmpSet.Get(RES_CHRATR_CJK_FONTSIZE);
98 return (sal_uInt16)aDefaultFontItem.GetHeight();
99 }
100
101
102
103 /*************************************************************************
104 |*
105 |* SwFntCache::Flush()
106 |*
107 |* Ersterstellung AMA 16. Dez. 94
108 |* Letzte Aenderung AMA 16. Dez. 94
109 |*
110 |*************************************************************************/
111
Flush()112 void SwFntCache::Flush( )
113 {
114 if ( pLastFont )
115 {
116 pLastFont->Unlock();
117 pLastFont = NULL;
118 }
119 SwCache::Flush( );
120 }
121
122 /*************************************************************************
123 |*
124 |* SwFntObj::SwFntObj(), ~SwFntObj()
125 |*
126 |* Ersterstellung AMA 7. Nov. 94
127 |* Letzte Aenderung AMA 7. Nov. 94
128 |*
129 |*************************************************************************/
130
SwFntObj(const SwSubFont & rFont,const void * pOwn,ViewShell * pSh)131 SwFntObj::SwFntObj( const SwSubFont &rFont, const void *pOwn, ViewShell *pSh ) :
132 SwCacheObj( (void*)pOwn ),
133 aFont( rFont ),
134 pScrFont( NULL ),
135 pPrtFont( &aFont ),
136 pPrinter( NULL ),
137 nPropWidth( rFont.GetPropWidth() )
138 {
139 nZoom = pSh ? pSh->GetViewOptions()->GetZoom() : USHRT_MAX;
140 nGuessedLeading = USHRT_MAX;
141 nExtLeading = USHRT_MAX;
142 nPrtAscent = USHRT_MAX;
143 nPrtHeight = USHRT_MAX;
144 bPaintBlank = ( UNDERLINE_NONE != aFont.GetUnderline()
145 || UNDERLINE_NONE != aFont.GetOverline()
146 || STRIKEOUT_NONE != aFont.GetStrikeout() )
147 && !aFont.IsWordLineMode();
148 aFont.SetLanguage(rFont.GetLanguage());
149 }
150
~SwFntObj()151 SwFntObj::~SwFntObj()
152 {
153 if ( pScrFont != pPrtFont )
154 delete pScrFont;
155 if ( pPrtFont != &aFont )
156 delete pPrtFont;
157 }
158
CreatePrtFont(const OutputDevice & rPrt)159 void SwFntObj::CreatePrtFont( const OutputDevice& rPrt )
160 {
161 if ( nPropWidth != 100 && pPrinter != &rPrt )
162 {
163 if( pScrFont != pPrtFont )
164 delete pScrFont;
165 if( pPrtFont != &aFont )
166 delete pPrtFont;
167
168 const Font aOldFnt( rPrt.GetFont() );
169 ((OutputDevice&)rPrt).SetFont( aFont );
170 const FontMetric aWinMet( rPrt.GetFontMetric() );
171 ((OutputDevice&)rPrt).SetFont( aOldFnt );
172 long nWidth = ( aWinMet.GetSize().Width() * nPropWidth ) / 100;
173
174 if( !nWidth )
175 ++nWidth;
176 pPrtFont = new Font( aFont );
177 pPrtFont->SetSize( Size( nWidth, aFont.GetSize().Height() ) );
178 pScrFont = NULL;
179 }
180 }
181
182 /*************************************************************************
183 *
184 * bool lcl_IsFontAdjustNecessary( rOutDev, rRefDev )
185 *
186 * returns whether we have to adjust the output font to resemble
187 * the formatting font
188 *
189 * _Not_ necessary if
190 *
191 * 1. RefDef == OutDev (text formatting, online layout...)
192 * 2. PDF export from online layout
193 * 3. Prospect/PagePreview pringing
194 *
195 *************************************************************************/
196
lcl_IsFontAdjustNecessary(const OutputDevice & rOutDev,const OutputDevice & rRefDev)197 bool lcl_IsFontAdjustNecessary( const OutputDevice& rOutDev,
198 const OutputDevice& rRefDev )
199 {
200 return &rRefDev != &rOutDev &&
201 OUTDEV_WINDOW != rRefDev.GetOutDevType() &&
202 ( OUTDEV_PRINTER != rRefDev.GetOutDevType() ||
203 OUTDEV_PRINTER != rOutDev.GetOutDevType() );
204 }
205
206 struct CalcLinePosData
207 {
208 SwDrawTextInfo& rInf;
209 Font& rFont;
210 xub_StrLen nCnt;
211 const sal_Bool bSwitchH2V;
212 const sal_Bool bSwitchL2R;
213 long nHalfSpace;
214 sal_Int32* pKernArray;
215 const sal_Bool bBidiPor;
216
CalcLinePosDataCalcLinePosData217 CalcLinePosData( SwDrawTextInfo& _rInf, Font& _rFont,
218 xub_StrLen _nCnt, const sal_Bool _bSwitchH2V, const sal_Bool _bSwitchL2R,
219 long _nHalfSpace, sal_Int32* _pKernArray, const sal_Bool _bBidiPor) :
220 rInf( _rInf ),
221 rFont( _rFont ),
222 nCnt( _nCnt ),
223 bSwitchH2V( _bSwitchH2V ),
224 bSwitchL2R( _bSwitchL2R ),
225 nHalfSpace( _nHalfSpace ),
226 pKernArray( _pKernArray ),
227 bBidiPor( _bBidiPor )
228 {
229 }
230 };
231
232 /** Function: lcl_calcLinePos
233
234 Computes the start and end position of an underline. This function is called
235 from the DrawText-method (for underlining misspelled words or smarttag terms).
236 */
237
lcl_calcLinePos(const CalcLinePosData & rData,Point & rStart,Point & rEnd,xub_StrLen nStart,xub_StrLen nWrLen)238 void lcl_calcLinePos( const CalcLinePosData &rData,
239 Point &rStart, Point &rEnd, xub_StrLen nStart, xub_StrLen nWrLen )
240 {
241 long nBlank = 0;
242 const xub_StrLen nEnd = nStart + nWrLen;
243 const long nTmpSpaceAdd = rData.rInf.GetSpace() / SPACING_PRECISION_FACTOR;
244
245 if ( nEnd < rData.nCnt
246 && CH_BLANK == rData.rInf.GetText().GetChar( rData.rInf.GetIdx() + nEnd ) )
247 {
248 if( nEnd + 1 == rData.nCnt )
249 nBlank -= nTmpSpaceAdd;
250 else
251 nBlank -= rData.nHalfSpace;
252 }
253
254 // determine start, end and length of wave line
255 sal_Int32 nKernStart = nStart ? rData.pKernArray[ sal_uInt16( nStart - 1 ) ] : 0;
256 sal_Int32 nKernEnd = rData.pKernArray[ sal_uInt16( nEnd - 1 ) ];
257
258 sal_uInt16 nDir = rData.bBidiPor ? 1800 :
259 UnMapDirection( rData.rFont.GetOrientation(), rData.bSwitchH2V );
260
261 switch ( nDir )
262 {
263 case 0 :
264 rStart.X() += nKernStart;
265 rEnd.X() = nBlank + rData.rInf.GetPos().X() + nKernEnd;
266 rEnd.Y() = rData.rInf.GetPos().Y();
267 break;
268 case 900 :
269 rStart.Y() -= nKernStart;
270 rEnd.X() = rData.rInf.GetPos().X();
271 rEnd.Y() = nBlank + rData.rInf.GetPos().Y() - nKernEnd;
272 break;
273 case 1800 :
274 rStart.X() -= nKernStart;
275 rEnd.X() = rData.rInf.GetPos().X() - nKernEnd - nBlank;
276 rEnd.Y() = rData.rInf.GetPos().Y();
277 break;
278 case 2700 :
279 rStart.Y() += nKernStart;
280 rEnd.X() = rData.rInf.GetPos().X();
281 rEnd.Y() = nBlank + rData.rInf.GetPos().Y() + nKernEnd;
282 break;
283 }
284
285 if ( rData.bSwitchL2R )
286 {
287 rData.rInf.GetFrm()->SwitchLTRtoRTL( rStart );
288 rData.rInf.GetFrm()->SwitchLTRtoRTL( rEnd );
289 }
290
291 if ( rData.bSwitchH2V )
292 {
293 rData.rInf.GetFrm()->SwitchHorizontalToVertical( rStart );
294 rData.rInf.GetFrm()->SwitchHorizontalToVertical( rEnd );
295 }
296 }
297
298 /*************************************************************************
299 *
300 * sal_uInt16 SwFntObj::GetFontAscent( const OutputDevice& rOut )
301 *
302 * Ersterstellung AMA 7. Nov. 94
303 * Letzte Aenderung AMA 7. Nov. 94
304 *
305 * Beschreibung: liefern den Ascent des Fonts auf dem
306 * gewuenschten Outputdevice zurueck, ggf. muss der Bildschirmfont erst
307 * erzeugt werden.
308 *************************************************************************/
309
GetFontAscent(const ViewShell * pSh,const OutputDevice & rOut)310 sal_uInt16 SwFntObj::GetFontAscent( const ViewShell *pSh, const OutputDevice& rOut )
311 {
312 sal_uInt16 nRet = 0;
313 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
314
315 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
316 {
317 CreateScrFont( *pSh, rOut );
318 ASSERT( USHRT_MAX != nScrAscent, "nScrAscent is going berzerk" )
319 nRet = nScrAscent;
320 }
321 else
322 {
323 if ( nPrtAscent == USHRT_MAX ) // DruckerAscent noch nicht bekannt?
324 {
325 CreatePrtFont( rOut );
326 const Font aOldFnt( rRefDev.GetFont() );
327 ((OutputDevice&)rRefDev).SetFont( *pPrtFont );
328 const FontMetric aOutMet( rRefDev.GetFontMetric() );
329 nPrtAscent = (sal_uInt16) aOutMet.GetAscent();
330 ( (OutputDevice&)rRefDev).SetFont( aOldFnt );
331 }
332
333 nRet = nPrtAscent;
334 }
335
336 #if !defined(MACOSX) // #i89844# extleading is below the line for Mac
337 // TODO: move extleading below the line for all platforms too
338 nRet += GetFontLeading( pSh, rRefDev );
339 #endif
340
341 ASSERT( USHRT_MAX != nRet, "GetFontAscent returned USHRT_MAX" )
342 return nRet;
343 }
344
345 /*************************************************************************
346 *
347 * sal_uInt16 SwFntObj::GetFontHeight( const OutputDevice* pOut )
348 *
349 * Ersterstellung AMA 7. Nov. 94
350 * Letzte Aenderung AMA 7. Nov. 94
351 *
352 * Beschreibung: liefern die H?he des Fonts auf dem
353 * gewuenschten Outputdevice zurueck, ggf. muss der Bildschirmfont erst
354 * erzeugt werden.
355 *************************************************************************/
356
GetFontHeight(const ViewShell * pSh,const OutputDevice & rOut)357 sal_uInt16 SwFntObj::GetFontHeight( const ViewShell* pSh, const OutputDevice& rOut )
358 {
359 sal_uInt16 nRet = 0;
360 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
361
362 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
363 {
364 CreateScrFont( *pSh, rOut );
365 ASSERT( USHRT_MAX != nScrHeight, "nScrHeight is going berzerk" )
366 nRet = nScrHeight + GetFontLeading( pSh, rRefDev );
367 }
368 else
369 {
370 if ( nPrtHeight == USHRT_MAX ) // PrinterHeight noch nicht bekannt?
371 {
372 CreatePrtFont( rOut );
373 const Font aOldFnt( rRefDev.GetFont() );
374 ((OutputDevice&)rRefDev).SetFont( *pPrtFont );
375 nPrtHeight = static_cast<sal_uInt16>(rRefDev.GetTextHeight());
376
377 #if OSL_DEBUG_LEVEL > 1
378 // Check if vcl did not change the meading of GetTextHeight
379 const FontMetric aOutMet( rRefDev.GetFontMetric() );
380 long nTmpPrtHeight = (sal_uInt16)aOutMet.GetAscent() + aOutMet.GetDescent();
381 (void) nTmpPrtHeight;
382 // #i106098#: do not compare with == here due to rounding error
383 ASSERT( abs(nTmpPrtHeight - nPrtHeight) < 3,
384 "GetTextHeight != Ascent + Descent" );
385 #endif
386
387 ((OutputDevice&)rRefDev).SetFont( aOldFnt );
388 }
389
390 nRet = nPrtHeight + GetFontLeading( pSh, rRefDev );
391 }
392
393 ASSERT( USHRT_MAX != nRet, "GetFontHeight returned USHRT_MAX" )
394 return nRet;
395 }
396
GetFontLeading(const ViewShell * pSh,const OutputDevice & rOut)397 sal_uInt16 SwFntObj::GetFontLeading( const ViewShell *pSh, const OutputDevice& rOut )
398 {
399 sal_uInt16 nRet = 0;
400
401 if ( pSh )
402 {
403 if ( USHRT_MAX == nGuessedLeading || USHRT_MAX == nExtLeading )
404 {
405 const Font aOldFnt( rOut.GetFont() );
406 ((OutputDevice&)rOut).SetFont( *pPrtFont );
407 const FontMetric aMet( rOut.GetFontMetric() );
408 ((OutputDevice&)rOut).SetFont( aOldFnt );
409 bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
410 GuessLeading( *pSh, aMet );
411 nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading());
412 }
413
414 const IDocumentSettingAccess& rIDSA = *pSh->getIDocumentSettingAccess();
415 const bool bBrowse = ( pSh->GetWin() &&
416 pSh->GetViewOptions()->getBrowseMode() &&
417 !pSh->GetViewOptions()->IsPrtFormat() );
418
419 if ( !bBrowse && rIDSA.get(IDocumentSettingAccess::ADD_EXT_LEADING) )
420 nRet = nExtLeading;
421 else
422 nRet = nGuessedLeading;
423 }
424
425 ASSERT( USHRT_MAX != nRet, "GetFontLeading returned USHRT_MAX" )
426 return nRet;
427 }
428
429
430 /*************************************************************************
431 *
432 * SwFntObj::CreateScrFont( const ViewShell& rSh, const OutputDevice& rOut )
433 *
434 * Ersterstellung AMA 7. Nov. 94
435 * Letzte Aenderung AMA 7. Nov. 94
436 *
437 * pOut is the output device, not the reference device
438 *
439 *************************************************************************/
440
CreateScrFont(const ViewShell & rSh,const OutputDevice & rOut)441 void SwFntObj::CreateScrFont( const ViewShell& rSh, const OutputDevice& rOut )
442 {
443 if ( pScrFont )
444 return;
445
446 // any changes to the output device are reset at the end of the function
447 OutputDevice* pOut = (OutputDevice*)&rOut;
448
449 // Save old font
450 Font aOldOutFont( pOut->GetFont() );
451
452 nScrHeight = USHRT_MAX;
453
454 // Condition for output font / refdev font adjustment
455 OutputDevice* pPrt = &rSh.GetRefDev();
456
457 if( !rSh.GetWin() ||
458 !rSh.GetViewOptions()->getBrowseMode() ||
459 rSh.GetViewOptions()->IsPrtFormat() )
460 {
461 // After CreatePrtFont pPrtFont is the font which is actually used
462 // by the reference device
463 CreatePrtFont( *pPrt );
464 pPrinter = pPrt;
465
466 // save old reference device font
467 Font aOldPrtFnt( pPrt->GetFont() );
468
469 // set the font used at the reference device at the reference device
470 // and the output device
471 pPrt->SetFont( *pPrtFont );
472 pOut->SetFont( *pPrtFont );
473
474 // This should be the default for pScrFont.
475 pScrFont = pPrtFont;
476
477 FontMetric aMet = pPrt->GetFontMetric( );
478 //Don't loose "faked" properties of the logical font that don't truly
479 //exist in the physical font metrics which vcl which fake up for us
480 aMet.SetWeight(pScrFont->GetWeight());
481 aMet.SetItalic(pScrFont->GetItalic());
482
483 bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
484
485 if ( USHRT_MAX == nGuessedLeading )
486 GuessLeading( rSh, aMet );
487
488 if ( USHRT_MAX == nExtLeading )
489 nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading());
490
491 // reset the original reference device font
492 pPrt->SetFont( aOldPrtFnt );
493 }
494 else
495 {
496 bSymbol = RTL_TEXTENCODING_SYMBOL == aFont.GetCharSet();
497 if ( nGuessedLeading == USHRT_MAX )
498 nGuessedLeading = 0;
499
500 // no external leading in browse mode
501 if ( nExtLeading == USHRT_MAX )
502 nExtLeading = 0;
503
504 pScrFont = pPrtFont;
505 }
506
507 // Zoomfaktor ueberpruefen, z.B. wg. PrtOle2 beim Speichern
508 {
509 // Sollte der Zoomfaktor des OutputDevices nicht mit dem der View-
510 // Options uebereinstimmen, so darf dieser Font nicht gecacht
511 // werden, deshalb wird der Zoomfaktor auf einen "ungueltigen" Wert
512 // gesetzt.
513 long nTmp;
514 if( pOut->GetMapMode().GetScaleX().IsValid() &&
515 pOut->GetMapMode().GetScaleY().IsValid() &&
516 pOut->GetMapMode().GetScaleX() == pOut->GetMapMode().GetScaleY() )
517 {
518 nTmp = ( 100 * pOut->GetMapMode().GetScaleX().GetNumerator() ) /
519 pOut->GetMapMode().GetScaleX().GetDenominator();
520 }
521 else
522 nTmp = 0;
523 if( nTmp != nZoom )
524 nZoom = USHRT_MAX - 1;
525 }
526
527 nScrAscent = (sal_uInt16)pOut->GetFontMetric().GetAscent();
528 if ( USHRT_MAX == nScrHeight )
529 nScrHeight = (sal_uInt16)pOut->GetTextHeight();
530
531 // reset original output device font
532 pOut->SetFont( aOldOutFont );
533 }
534
535
GuessLeading(const ViewShell & rSh,const FontMetric & rMet)536 void SwFntObj::GuessLeading( const ViewShell&
537 #if defined(WNT) || defined(PM2)
538 rSh
539 #endif
540 , const FontMetric& rMet )
541 {
542 // If leading >= 5, this seems to be enough leading.
543 // Nothing has to be done.
544 if ( rMet.GetIntLeading() >= 5 )
545 {
546 nGuessedLeading = 0;
547 return;
548 }
549
550 #if defined(WNT) || defined(PM2)
551 OutputDevice *pWin = rSh.GetWin() ?
552 rSh.GetWin() :
553 GetpApp()->GetDefaultDevice();
554 if ( pWin )
555 {
556 MapMode aTmpMap( MAP_TWIP );
557 MapMode aOldMap = pWin->GetMapMode( );
558 pWin->SetMapMode( aTmpMap );
559 const Font aOldFnt( pWin->GetFont() );
560 pWin->SetFont( *pPrtFont );
561 const FontMetric aWinMet( pWin->GetFontMetric() );
562 const sal_uInt16 nWinHeight = sal_uInt16( aWinMet.GetSize().Height() );
563 if( pPrtFont->GetName().Search( aWinMet.GetName() ) < USHRT_MAX )
564 {
565 // Wenn das Leading auf dem Window auch 0 ist, dann
566 // muss es auch so bleiben (vgl. StarMath!).
567 long nTmpLeading = (long)aWinMet.GetIntLeading();
568 // einen Versuch haben wir noch wg. 31003:
569 if( nTmpLeading <= 0 )
570 {
571 pWin->SetFont( rMet );
572 nTmpLeading = (long)pWin->GetFontMetric().GetIntLeading();
573 if( nTmpLeading < 0 )
574 nGuessedLeading = 0;
575 else
576 nGuessedLeading = sal_uInt16(nTmpLeading);
577 }
578 else
579 {
580 nGuessedLeading = sal_uInt16(nTmpLeading);
581 // Manta-Hack #50153#:
582 // Wer beim Leading luegt, luegt moeglicherweise auch beim
583 // Ascent/Descent, deshalb wird hier ggf. der Font ein wenig
584 // tiefergelegt, ohne dabei seine Hoehe zu aendern.
585 long nDiff = Min( rMet.GetDescent() - aWinMet.GetDescent(),
586 aWinMet.GetAscent() - rMet.GetAscent() - nTmpLeading );
587 if( nDiff > 0 )
588 {
589 ASSERT( nPrtAscent < USHRT_MAX, "GuessLeading: PrtAscent-Fault" );
590 if ( nPrtAscent < USHRT_MAX )
591 nPrtAscent = nPrtAscent + (sal_uInt16)(( 2 * nDiff ) / 5);
592 }
593 }
594 }
595 else
596 {
597 // Wenn alle Stricke reissen, nehmen wir 15% der
598 // Hoehe, ein von CL empirisch ermittelter Wert.
599 nGuessedLeading = (nWinHeight * 15) / 100;
600 }
601 pWin->SetFont( aOldFnt );
602 pWin->SetMapMode( aOldMap );
603 }
604 else
605 #endif
606 nGuessedLeading = 0;
607 }
608
609 /*************************************************************************
610 *
611 * void SwFntObj::SetDeviceFont( const OutputDevice *pOut ),
612 *
613 * Ersterstellung AMA 7. Nov. 94
614 * Letzte Aenderung AMA 7. Nov. 94
615 *
616 * Beschreibung: stellt den Font am gewuenschten OutputDevice ein,
617 * am Bildschirm muss eventuell erst den Abgleich durchgefuehrt werden.
618 *
619 *************************************************************************/
620
SetDevFont(const ViewShell * pSh,OutputDevice & rOut)621 void SwFntObj::SetDevFont( const ViewShell *pSh, OutputDevice& rOut )
622 {
623 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
624
625 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
626 {
627 CreateScrFont( *pSh, rOut );
628 if( !GetScrFont()->IsSameInstance( rOut.GetFont() ) )
629 rOut.SetFont( *pScrFont );
630 if( pPrinter && ( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) )
631 pPrinter->SetFont( *pPrtFont );
632 }
633 else
634 {
635 CreatePrtFont( rOut );
636 if( !pPrtFont->IsSameInstance( rOut.GetFont() ) )
637 rOut.SetFont( *pPrtFont );
638 }
639
640 // Here, we actually do not need the leading values, but by calling
641 // GetFontLeading() we assure that the values are calculated for later use.
642 GetFontLeading( pSh, rRefDev );
643 }
644
645 #define WRONG_SHOW_MIN 5
646 #define WRONG_SHOW_SMALL 11
647 #define WRONG_SHOW_MEDIUM 15
648
649 /*************************************************************************
650 *
651 * void SwFntObj::DrawText( ... )
652 *
653 * Ersterstellung AMA 16. Dez. 94
654 * Letzte Aenderung AMA 16. Dez. 94
655 *
656 * Beschreibung: Textausgabe
657 * auf dem Bildschirm => DrawTextArray
658 * auf dem Drucker, !Kerning => DrawText
659 * auf dem Drucker + Kerning => DrawStretchText
660 *
661 *************************************************************************/
662
lcl_WhichPunctuation(xub_Unicode cChar)663 sal_uInt8 lcl_WhichPunctuation( xub_Unicode cChar )
664 {
665 if ( ( cChar < 0x3001 || cChar > 0x3002 ) &&
666 ( cChar < 0x3008 || cChar > 0x3011 ) &&
667 ( cChar < 0x3014 || cChar > 0x301F ) &&
668 0xFF62 != cChar && 0xFF63 != cChar )
669 // no punctuation
670 return SwScriptInfo::NONE;
671 else if ( 0x3001 == cChar || 0x3002 == cChar ||
672 0x3009 == cChar || 0x300B == cChar ||
673 0x300D == cChar || 0x300F == cChar ||
674 0x3011 == cChar || 0x3015 == cChar ||
675 0x3017 == cChar || 0x3019 == cChar ||
676 0x301B == cChar || 0x301E == cChar ||
677 0x301F == cChar || 0xFF63 == cChar )
678 // right punctuation
679 return SwScriptInfo::SPECIAL_RIGHT;
680
681 return SwScriptInfo::SPECIAL_LEFT;
682 }
683
lcl_IsMonoSpaceFont(const OutputDevice & rOut)684 static sal_Bool lcl_IsMonoSpaceFont( const OutputDevice& rOut )
685 {
686 const String aStr1( xub_Unicode( 0x3008 ) );
687 const String aStr2( xub_Unicode( 0x307C ) );
688 const long nWidth1 = rOut.GetTextWidth( aStr1 );
689 const long nWidth2 = rOut.GetTextWidth( aStr2 );
690 return nWidth1 == nWidth2;
691 }
692
693 // ER 09.07.95 20:34
694 // mit -Ox Optimierung stuerzt's unter win95 ab
695 // JP 12.07.95: unter WNT auch (i386); Alpha ??
696 // global optimization off
697 #ifdef _MSC_VER
698 #pragma optimize("g",off)
699 #endif
700
701 /* This helper structure (SwForbidden) contains the already marked parts of the string
702 to avoid double lines (e.g grammar + spell check error) */
703
704 typedef std::vector< std::pair< xub_StrLen, xub_StrLen > > SwForbidden;
705
lcl_DrawLineForWrongListData(SwForbidden & rForbidden,const SwDrawTextInfo & rInf,const SwWrongList * pWList,const CalcLinePosData & rCalcLinePosData,const Size & rPrtFontSize)706 static void lcl_DrawLineForWrongListData(
707 SwForbidden &rForbidden,
708 const SwDrawTextInfo &rInf,
709 const SwWrongList *pWList,
710 const CalcLinePosData &rCalcLinePosData,
711 const Size &rPrtFontSize )
712 {
713 if (!pWList) return;
714
715 xub_StrLen nStart = rInf.GetIdx();
716 xub_StrLen nWrLen = rInf.GetLen();
717
718 // check if respective data is available in the current text range
719 if (!pWList->Check( nStart, nWrLen ))
720 {
721 return;
722 }
723
724 long nHght = rInf.GetOut().LogicToPixel( rPrtFontSize ).Height();
725
726 // Draw wavy lines for spell and grammar errors only if font is large enough.
727 // Lines for smart tags will always be drawn.
728 if (pWList != rInf.GetSmartTags() && WRONG_SHOW_MIN >= nHght)
729 {
730 return;
731 }
732
733 SwForbidden::iterator pIter = rForbidden.begin();
734 if (rInf.GetOut().GetConnectMetaFile())
735 rInf.GetOut().Push();
736
737 const Color aCol( rInf.GetOut().GetLineColor() );
738
739 // iterate over all ranges stored in the respective SwWrongList
740 do
741 {
742 nStart = nStart - rInf.GetIdx();
743
744 const xub_StrLen nEnd = nStart + nWrLen;
745 xub_StrLen nNext = nStart;
746 while( nNext < nEnd )
747 {
748 while( pIter != rForbidden.end() && pIter->second <= nNext )
749 ++pIter;
750
751 xub_StrLen nNextStart = nNext;
752 xub_StrLen nNextEnd = nEnd;
753
754 if( pIter == rForbidden.end() || nNextEnd <= pIter->first )
755 {
756 // No overlapping mark up found
757 std::pair< xub_StrLen, xub_StrLen > aNew;
758 aNew.first = nNextStart;
759 aNew.second = nNextEnd;
760 rForbidden.insert( pIter, aNew );
761 pIter = rForbidden.begin();
762 nNext = nEnd;
763 }
764 else
765 {
766 nNext = pIter->second;
767 if( nNextStart < pIter->first )
768 {
769 nNextEnd = pIter->first;
770 pIter->first = nNextStart;
771 }
772 else
773 continue;
774 }
775 // determine line pos
776 Point aStart( rInf.GetPos() );
777 Point aEnd;
778 lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart );
779
780
781 sal_uInt16 wrongPos = pWList->GetWrongPos(nNextStart + rInf.GetIdx());
782
783 const SwWrongArea* wrongArea = pWList->GetElement(wrongPos);
784
785 if (wrongArea != 0)
786 {
787 if (WRONGAREA_DASHED == wrongArea->mLineType)
788 {
789 rInf.GetOut().SetLineColor( wrongArea->mColor );
790
791 aStart.Y() +=30;
792 aEnd.Y() +=30;
793
794 LineInfo aLineInfo( LINE_DASH );
795 aLineInfo.SetDistance( 40 );
796 aLineInfo.SetDashLen( 1 );
797 aLineInfo.SetDashCount(1);
798
799 rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
800 }
801 else if (WRONGAREA_WAVE == wrongArea->mLineType)
802 {
803 rInf.GetOut().SetLineColor( wrongArea->mColor );
804
805 // get wavy line type to use
806 sal_uInt16 nWave =
807 WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL :
808 ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL : WAVE_FLAT );
809
810 rInf.GetOut().DrawWaveLine( aStart, aEnd, nWave );
811 }
812 else if (WRONGAREA_WAVE_NORMAL == wrongArea->mLineType)
813 {
814 rInf.GetOut().SetLineColor( wrongArea->mColor );
815
816 rInf.GetOut().DrawWaveLine( aStart, aEnd, WAVE_NORMAL);
817 }
818
819 else if (WRONGAREA_WAVE_SMALL == wrongArea->mLineType)
820 {
821 rInf.GetOut().SetLineColor( wrongArea->mColor );
822
823 rInf.GetOut().DrawWaveLine( aStart, aEnd, WAVE_SMALL);
824 }
825 else if (WRONGAREA_WAVE_FLAT == wrongArea->mLineType)
826 {
827 rInf.GetOut().SetLineColor( wrongArea->mColor );
828
829 rInf.GetOut().DrawWaveLine( aStart, aEnd, WAVE_FLAT);
830 }
831 }
832 }
833
834 nStart = nEnd + rInf.GetIdx();
835 nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart;
836 }
837 while (nWrLen && pWList->Check( nStart, nWrLen ));
838
839 rInf.GetOut().SetLineColor( aCol );
840
841 if (rInf.GetOut().GetConnectMetaFile())
842 rInf.GetOut().Pop();
843 }
844
845
DrawText(SwDrawTextInfo & rInf)846 void SwFntObj::DrawText( SwDrawTextInfo &rInf )
847 {
848 ASSERT( rInf.GetShell(), "SwFntObj::DrawText without shell" )
849
850 OutputDevice& rRefDev = rInf.GetShell()->GetRefDev();
851 OutputDevice* pWin = rInf.GetShell()->GetWin();
852
853 // true if pOut is the printer and the printer has been used for formatting
854 const sal_Bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() &&
855 OUTDEV_PRINTER == rRefDev.GetOutDevType();
856 const sal_Bool bBrowse = ( pWin &&
857 rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
858 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() &&
859 !rInf.GetBullet() &&
860 ( rInf.GetSpace() || !rInf.GetKern() ) &&
861 !rInf.GetWrong() &&
862 !rInf.GetGrammarCheck() &&
863 !rInf.GetSmartTags() &&
864 !rInf.GetGreyWave() );
865
866 // bDirectPrint indicates that we can enter the branch which calls
867 // the DrawText functions instead of calling the DrawTextArray functions
868 const sal_Bool bDirectPrint = bPrt || bBrowse;
869
870 // Condition for output font / refdev font adjustment
871 const sal_Bool bUseScrFont =
872 lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev );
873
874 Font* pTmpFont = bUseScrFont ? pScrFont : pPrtFont;
875
876 //
877 // bDirectPrint and bUseScrFont should have these values:
878 //
879 // Outdev / RefDef | Printer | VirtPrinter | Window
880 // ----------------------------------------------------
881 // Printer | 1 - 0 | 0 - 1 | -
882 // ----------------------------------------------------
883 // VirtPrinter/PDF | 0 - 1 | 0 - 1 | -
884 // ----------------------------------------------------
885 // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0
886 //
887 // Exception: During painting of a Writer OLE object, we do not have
888 // a window. Therefore bUseSrcFont is always 0 in this case.
889 //
890
891 #ifdef DBG_UTIL
892
893 const sal_Bool bNoAdjust = bPrt ||
894 ( pWin &&
895 rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
896 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() );
897
898 if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() )
899 {
900 // Printer output
901 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
902 {
903 ASSERT( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" )
904 }
905 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() )
906 {
907 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" )
908 }
909 else
910 {
911 ASSERT( sal_False, "Outdev Check failed" )
912 }
913 }
914 else if ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && ! pWin )
915 {
916 // PDF export
917 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
918 {
919 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" )
920 }
921 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() )
922 {
923 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" )
924 }
925 else
926 {
927 ASSERT( sal_False, "Outdev Check failed" )
928 }
929 }
930 else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() ||
931 ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && pWin ) )
932 {
933 // Window or virtual window
934 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
935 {
936 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" )
937 }
938 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() )
939 {
940 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" )
941 }
942 else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() )
943 {
944 ASSERT( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" )
945 }
946 else
947 {
948 ASSERT( sal_False, "Outdev Check failed" )
949 }
950 }
951 else
952 {
953 ASSERT( sal_False, "Outdev Check failed" )
954 }
955
956 #endif
957
958 // robust: better use the printer font instead of using no font at all
959 ASSERT( pTmpFont, "No screen or printer font?" );
960 if ( ! pTmpFont )
961 pTmpFont = pPrtFont;
962
963 // HACK: UNDERLINE_WAVE darf nicht mehr missbraucht werden, daher
964 // wird die graue Wellenlinie des ExtendedAttributSets zunaechst
965 // in der Fontfarbe erscheinen.
966
967 const sal_Bool bSwitchH2V = rInf.GetFrm() && rInf.GetFrm()->IsVertical();
968 const sal_Bool bSwitchL2R = rInf.GetFrm() && rInf.GetFrm()->IsRightToLeft() &&
969 ! rInf.IsIgnoreFrmRTL();
970 const sal_uLong nMode = rInf.GetOut().GetLayoutMode();
971 const sal_Bool bBidiPor = ( bSwitchL2R !=
972 ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) );
973
974 // be sure to have the correct layout mode at the printer
975 if ( pPrinter )
976 {
977 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
978 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
979 }
980
981 Point aPos( rInf.GetPos() );
982 if( !bPrt )
983 {
984 if( rInf.GetpOut() != pPixOut || rInf.GetOut().GetMapMode() != *pPixMap )
985 {
986 *pPixMap = rInf.GetOut().GetMapMode();
987 pPixOut = rInf.GetpOut();
988 Size aTmp( 1, 1 );
989 nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width();
990 }
991
992 aPos.X() += rInf.GetFrm()->IsRightToLeft() ? 0 : nPixWidth;
993 }
994
995 Color aOldColor( pTmpFont->GetColor() );
996 sal_Bool bChgColor = rInf.ApplyAutoColor( pTmpFont );
997 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
998 rInf.GetOut().SetFont( *pTmpFont );
999 if ( bChgColor )
1000 pTmpFont->SetColor( aOldColor );
1001
1002 if ( STRING_LEN == rInf.GetLen() )
1003 rInf.SetLen( rInf.GetText().Len() );
1004
1005
1006 //
1007 // ASIAN LINE AND CHARACTER GRID MODE START: snap to characters
1008 //
1009
1010 if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() &&
1011 SW_CJK == rInf.GetFont()->GetActual() )
1012 {
1013 GETGRID( rInf.GetFrm()->FindPageFrm() )
1014 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
1015 {
1016 //for textgrid refactor
1017 //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
1018 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1019 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
1020 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
1021
1022 if ( pPrinter )
1023 pPrinter->GetTextArray( rInf.GetText(), pKernArray,
1024 rInf.GetIdx(), rInf.GetLen() );
1025 else
1026 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1027 rInf.GetIdx(), rInf.GetLen() );
1028
1029 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
1030
1031 const sal_uLong i = nWidthPerChar ?
1032 ( nWidthPerChar - 1 ) / nGridWidth + 1:
1033 1;
1034
1035 nWidthPerChar = i * nGridWidth;
1036
1037 // position of first character, we take the printer position
1038 long nCharWidth = pKernArray[ 0 ];
1039 sal_uLong nHalfWidth = nWidthPerChar / 2;
1040
1041 long nNextFix;
1042
1043 // punctuation characters are not centered
1044 xub_Unicode cChar = rInf.GetText().GetChar( rInf.GetIdx() );
1045 sal_uInt8 nType = lcl_WhichPunctuation( cChar );
1046 switch ( nType )
1047 {
1048 case SwScriptInfo::NONE :
1049 aPos.X() += ( nWidthPerChar - nCharWidth ) / 2;
1050 nNextFix = nCharWidth / 2;
1051 break;
1052 case SwScriptInfo::SPECIAL_RIGHT :
1053 nNextFix = nHalfWidth;
1054 break;
1055 default:
1056 aPos.X() += nWidthPerChar - nCharWidth;
1057 nNextFix = nCharWidth - nHalfWidth;
1058 }
1059
1060 // calculate offsets
1061 for ( xub_StrLen j = 1; j < rInf.GetLen(); ++j )
1062 {
1063 long nScr = pKernArray[ j ] - pKernArray[ j - 1 ];
1064 nNextFix += nWidthPerChar;
1065
1066 // punctuation characters are not centered
1067 cChar = rInf.GetText().GetChar( rInf.GetIdx() + j );
1068 nType = lcl_WhichPunctuation( cChar );
1069 switch ( nType )
1070 {
1071 case SwScriptInfo::NONE :
1072 pKernArray[ j - 1 ] = nNextFix - ( nScr / 2 );
1073 break;
1074 case SwScriptInfo::SPECIAL_RIGHT :
1075 pKernArray[ j - 1 ] = nNextFix - nHalfWidth;
1076 break;
1077 default:
1078 pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nScr;
1079 }
1080 }
1081
1082 // the layout engine requires the total width of the output
1083 pKernArray[ rInf.GetLen() - 1 ] = rInf.GetWidth() -
1084 aPos.X() + rInf.GetPos().X() ;
1085
1086 if ( bSwitchH2V )
1087 rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
1088
1089 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1090 pKernArray, rInf.GetIdx(), rInf.GetLen() );
1091
1092 delete[] pKernArray;
1093 return;
1094 }
1095 }
1096
1097 // For text grid refactor
1098 // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters
1099 //
1100 if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() &&
1101 SW_CJK == rInf.GetFont()->GetActual() )
1102 {
1103 GETGRID( rInf.GetFrm()->FindPageFrm() )
1104
1105 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1106 {
1107 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
1108
1109 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1110 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
1111 if( SW_LATIN == rInf.GetFont()->GetActual() )
1112 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2;
1113 else
1114 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
1115
1116 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
1117
1118 if ( pPrinter )
1119 pPrinter->GetTextArray( rInf.GetText(), pKernArray,
1120 rInf.GetIdx(), rInf.GetLen() );
1121 else
1122 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1123 rInf.GetIdx(), rInf.GetLen() );
1124 if ( bSwitchH2V )
1125 rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
1126 if ( rInf.GetSpace() || rInf.GetKanaComp())
1127 {
1128 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1129 sal_Bool bSpecialJust = sal_False;
1130 if ( rInf.GetFont() && rInf.GetLen() )
1131 {
1132 const SwScriptInfo* pSI = rInf.GetScriptInfo();
1133 const sal_uInt8 nActual = rInf.GetFont()->GetActual();
1134 ///Kana Compression
1135 if( SW_CJK == nActual && rInf.GetKanaComp() &&
1136 pSI && pSI->CountCompChg() &&
1137 lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) )
1138 {
1139 pSI->Compress( pKernArray,rInf.GetIdx(), rInf.GetLen(),
1140 rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(),&aPos );
1141 bSpecialJust = sal_True;
1142 }
1143 ///Asian Justification
1144 if ( ( SW_CJK == nActual || SW_LATIN == nActual ) && nSpaceAdd )
1145 {
1146 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
1147 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang)
1148 {
1149 long nSpaceSum = nSpaceAdd;
1150 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
1151 {
1152 pKernArray[ nI ] += nSpaceSum;
1153 nSpaceSum += nSpaceAdd;
1154 }
1155 bSpecialJust = sal_True;
1156 nSpaceAdd = 0;
1157 }
1158 }
1159 long nGridAddSum = nGridWidthAdd;
1160 for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd )
1161 {
1162 pKernArray[i] += nGridAddSum;
1163 }
1164 long nKernSum = rInf.GetKern();
1165 if ( bSpecialJust || rInf.GetKern() )
1166 {
1167 for( xub_StrLen i = 0; i < rInf.GetLen(); i++, nKernSum += rInf.GetKern() )
1168 {
1169 if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) )
1170 nKernSum += nSpaceAdd;
1171 pKernArray[i] += nKernSum;
1172 }
1173 ///With through/uderstr. Grouped style requires a blank at the end
1174 ///of a text edition special measures:
1175 if( bPaintBlank && rInf.GetLen() && (CH_BLANK ==
1176 rInf.GetText().GetChar( rInf.GetIdx() + rInf.GetLen() - 1) ) )
1177 {
1178 ///If it concerns a singular, underlined space acts,
1179 ///we must spend two:
1180 if( 1 == rInf.GetLen() )
1181 {
1182 pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1183 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1184 pKernArray, rInf.GetIdx(), 1 );
1185 }
1186 else
1187 {
1188 pKernArray[ rInf.GetLen() - 2] += nSpaceAdd;
1189 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1190 pKernArray, rInf.GetIdx(), rInf.GetLen() );
1191 }
1192 }
1193 else
1194 {
1195 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1196 pKernArray, rInf.GetIdx(), rInf.GetLen() );
1197 }
1198 }
1199 else
1200 {
1201 Point aTmpPos( aPos );
1202 xub_StrLen i;
1203 xub_StrLen j = 0;
1204 long nSpaceSum = 0;
1205 for( i = 0; i < rInf.GetLen(); i++ )
1206 {
1207 if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx() + i) )
1208 {
1209 nSpaceSum += nSpaceAdd;
1210 if( j < i)
1211 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1212 rInf.GetIdx() + j, i - j );
1213 j = i + 1;
1214 pKernArray[i] = pKernArray[i] + nSpaceSum;
1215 aTmpPos.X() = aPos.X() + pKernArray[ i ] + nKernSum;
1216 }
1217 }
1218 if( j < i )
1219 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1220 rInf.GetIdx() +j , i - j );
1221 }
1222 }
1223 }
1224 else
1225 {
1226 //long nKernAdd = rInf.GetKern();
1227 long nKernAdd = 0;
1228 long nGridAddSum = nGridWidthAdd + nKernAdd;
1229 for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd + nKernAdd )
1230 {
1231 pKernArray[i] += nGridAddSum;
1232 }
1233 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1234 pKernArray, rInf.GetIdx(), rInf.GetLen() );
1235 }
1236 delete[] pKernArray;
1237 return;
1238 }
1239 }
1240
1241 //
1242 // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT
1243 //
1244
1245 if ( bDirectPrint )
1246 {
1247 const Fraction aTmp( 1, 1 );
1248 sal_Bool bStretch = rInf.GetWidth() && ( rInf.GetLen() > 1 ) && bPrt
1249 && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() );
1250
1251 if ( bSwitchL2R )
1252 rInf.GetFrm()->SwitchLTRtoRTL( aPos );
1253
1254 if ( bSwitchH2V )
1255 rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
1256
1257 // In the good old days we used to have a simple DrawText if the
1258 // output device is the printer. Now we need a DrawTextArray if
1259 // 1. KanaCompression is enabled
1260 // 2. Justified alignment
1261 // Simple kerning is handled by DrawStretchText
1262 if( rInf.GetSpace() || rInf.GetKanaComp() )
1263 {
1264 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ];
1265 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1266 rInf.GetIdx(), rInf.GetLen() );
1267
1268 if( bStretch )
1269 {
1270 xub_StrLen nZwi = rInf.GetLen() - 1;
1271 long nDiff = rInf.GetWidth() - pKernArray[ nZwi ]
1272 - rInf.GetLen() * rInf.GetKern();
1273 long nRest = nDiff % nZwi;
1274 long nAdd;
1275 if( nRest < 0 )
1276 {
1277 nAdd = -1;
1278 nRest += nZwi;
1279 }
1280 else
1281 {
1282 nAdd = +1;
1283 nRest = nZwi - nRest;
1284 }
1285 nDiff /= nZwi;
1286 long nSum = nDiff;
1287 for( xub_StrLen i = 0; i < nZwi; )
1288 {
1289 pKernArray[ i ] += nSum;
1290 if( ++i == nRest )
1291 nDiff += nAdd;
1292 nSum += nDiff;
1293 }
1294 }
1295
1296 //
1297 // Modify Array for special justifications
1298 //
1299 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1300 sal_Bool bSpecialJust = sal_False;
1301
1302 if ( rInf.GetFont() && rInf.GetLen() )
1303 {
1304 const SwScriptInfo* pSI = rInf.GetScriptInfo();
1305 const sal_uInt8 nActual = rInf.GetFont()->GetActual();
1306
1307 // Kana Compression
1308 if ( SW_CJK == nActual && rInf.GetKanaComp() &&
1309 pSI && pSI->CountCompChg() &&
1310 lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1311 {
1312 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
1313 rInf.GetKanaComp(),
1314 (sal_uInt16)aFont.GetSize().Height(), &aPos );
1315 bSpecialJust = sal_True;
1316 }
1317
1318 // Asian Justification
1319 if ( SW_CJK == nActual && nSpaceAdd )
1320 {
1321 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
1322
1323 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
1324 {
1325 long nSpaceSum = nSpaceAdd;
1326 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
1327 {
1328 pKernArray[ nI ] += nSpaceSum;
1329 nSpaceSum += nSpaceAdd;
1330 }
1331
1332 bSpecialJust = sal_True;
1333 nSpaceAdd = 0;
1334 }
1335 }
1336
1337 // Kashida Justification
1338 if ( SW_CTL == nActual && nSpaceAdd )
1339 {
1340 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1341 {
1342 if ( pSI && pSI->CountKashida() &&
1343 pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(),
1344 rInf.GetLen(), nSpaceAdd ) != STRING_LEN )
1345 {
1346 bSpecialJust = sal_True;
1347 nSpaceAdd = 0;
1348 }
1349 }
1350 }
1351
1352 // Thai Justification
1353 if ( SW_CTL == nActual && nSpaceAdd )
1354 {
1355 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
1356
1357 if ( LANGUAGE_THAI == aLang )
1358 {
1359 // Use rInf.GetSpace() because it has more precision than
1360 // nSpaceAdd:
1361 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0,
1362 rInf.GetIdx(), rInf.GetLen(),
1363 rInf.GetNumberOfBlanks(),
1364 rInf.GetSpace() );
1365
1366 // adding space to blanks is already done
1367 bSpecialJust = sal_True;
1368 nSpaceAdd = 0;
1369 }
1370 }
1371 }
1372
1373 long nKernSum = rInf.GetKern();
1374
1375 if ( bStretch || bPaintBlank || rInf.GetKern() || bSpecialJust )
1376 {
1377 for( xub_StrLen i = 0; i < rInf.GetLen(); i++,
1378 nKernSum += rInf.GetKern() )
1379 {
1380 if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) )
1381 nKernSum += nSpaceAdd;
1382 pKernArray[i] += nKernSum;
1383 }
1384
1385 // Bei durch/unterstr. Blocksatz erfordert ein Blank am Ende
1386 // einer Textausgabe besondere Massnahmen:
1387 if( bPaintBlank && rInf.GetLen() && ( CH_BLANK ==
1388 rInf.GetText().GetChar( rInf.GetIdx()+rInf.GetLen()-1 ) ) )
1389 {
1390 // Wenn es sich um ein singulaeres, unterstrichenes Space
1391 // handelt, muessen wir zwei ausgeben:
1392 if( 1 == rInf.GetLen() )
1393 {
1394 pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1395
1396 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1397 pKernArray, rInf.GetIdx(), 1 );
1398 }
1399 else
1400 {
1401 pKernArray[ rInf.GetLen() - 2 ] += nSpaceAdd;
1402 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1403 pKernArray, rInf.GetIdx(), rInf.GetLen() );
1404 }
1405 }
1406 else
1407 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1408 pKernArray, rInf.GetIdx(), rInf.GetLen() );
1409 }
1410 else
1411 {
1412 Point aTmpPos( aPos );
1413 xub_StrLen j = 0;
1414 xub_StrLen i;
1415 for( i = 0; i < rInf.GetLen(); i++ )
1416 {
1417 if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx()+i ) )
1418 {
1419 nKernSum += nSpaceAdd;
1420 if( j < i )
1421 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1422 rInf.GetIdx() + j, i - j );
1423 j = i + 1;
1424 SwTwips nAdd = pKernArray[ i ] + nKernSum;
1425 if ( ( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ) == nMode )
1426 nAdd *= -1;
1427 aTmpPos.X() = aPos.X() + nAdd;
1428 }
1429 }
1430 if( j < i )
1431 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1432 rInf.GetIdx() + j, i - j );
1433 }
1434 delete[] pKernArray;
1435 }
1436 else if( bStretch )
1437 {
1438 long nTmpWidth = rInf.GetWidth();
1439 if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() )
1440 nTmpWidth -= rInf.GetKern();
1441 rInf.GetOut().DrawStretchText( aPos, nTmpWidth,
1442 rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
1443 }
1444 else if( rInf.GetKern() )
1445 {
1446 const long nTmpWidth = GetTextSize( rInf ).Width();
1447
1448 const Color aSaveColor( pTmpFont->GetColor() );
1449 const sal_Bool bColorChanged = rInf.ApplyAutoColor( pTmpFont );
1450
1451 if( bColorChanged )
1452 {
1453 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1454 rInf.GetOut().SetFont( *pTmpFont );
1455 pTmpFont->SetColor( aSaveColor );
1456 }
1457
1458 rInf.GetOut().DrawStretchText( aPos, (sal_uInt16)nTmpWidth,
1459 rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
1460 }
1461 else
1462 rInf.GetOut().DrawText( aPos, rInf.GetText(),
1463 rInf.GetIdx(), rInf.GetLen() );
1464 }
1465
1466 //
1467 // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT
1468 //
1469
1470 else
1471 {
1472 const String* pStr = &rInf.GetText();
1473 String aStr( aEmptyStr );
1474 sal_Bool bBullet = rInf.GetBullet();
1475 if( bSymbol )
1476 bBullet = sal_False;
1477 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ];
1478 CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1479 long nScrPos;
1480
1481 // get screen array
1482 sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ];
1483 rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray,
1484 rInf.GetIdx(), rInf.GetLen() );
1485
1486 // OLE: no printer available
1487 // ASSERT( pPrinter, "DrawText needs pPrinter" )
1488 if ( pPrinter )
1489 {
1490 // pTmpFont has already been set as current font for rInf.GetOut()
1491 if ( pPrinter != rInf.GetpOut() || pTmpFont != pPrtFont )
1492 {
1493 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1494 pPrinter->SetFont( *pPrtFont );
1495 }
1496 pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),
1497 rInf.GetLen() );
1498 }
1499 else
1500 {
1501 // sal_Bool bRestore = sal_False;
1502 // MapMode aOld( rInf.GetOut().GetMapMode() );
1503 // if( rInf.GetZoom().GetNumerator() &&
1504 // rInf.GetZoom() != aOld.GetScaleX() )
1505 // {
1506 // MapMode aNew( aOld );
1507 // aNew.SetScaleX( rInf.GetZoom() );
1508 // aNew.SetScaleY( rInf.GetZoom() );
1509 // rInf.GetOut().SetMapMode( aNew );
1510 // bRestore = sal_True;
1511 // }
1512 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1513 rInf.GetIdx(), rInf.GetLen() );
1514 // if( bRestore )
1515 // rInf.GetOut().SetMapMode( aOld );
1516 }
1517
1518 //
1519 // Modify Printer and ScreenArrays for special justifications
1520 //
1521 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1522 bool bNoHalfSpace = false;
1523
1524 if ( rInf.GetFont() && rInf.GetLen() )
1525 {
1526 const sal_uInt8 nActual = rInf.GetFont()->GetActual();
1527 const SwScriptInfo* pSI = rInf.GetScriptInfo();
1528
1529 // Kana Compression
1530 if ( SW_CJK == nActual && rInf.GetKanaComp() &&
1531 pSI && pSI->CountCompChg() &&
1532 lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1533 {
1534 Point aTmpPos( aPos );
1535 pSI->Compress( pScrArray, rInf.GetIdx(), rInf.GetLen(),
1536 rInf.GetKanaComp(),
1537 (sal_uInt16)aFont.GetSize().Height(), &aTmpPos );
1538 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
1539 rInf.GetKanaComp(),
1540 (sal_uInt16)aFont.GetSize().Height(), &aPos );
1541 }
1542
1543 // Asian Justification
1544 if ( SW_CJK == nActual && nSpaceAdd )
1545 {
1546 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
1547
1548 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
1549 {
1550 long nSpaceSum = nSpaceAdd;
1551 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
1552 {
1553 pKernArray[ nI ] += nSpaceSum;
1554 pScrArray[ nI ] += nSpaceSum;
1555 nSpaceSum += nSpaceAdd;
1556 }
1557
1558 nSpaceAdd = 0;
1559 }
1560 }
1561
1562 // Kashida Justification
1563 if ( SW_CTL == nActual && nSpaceAdd )
1564 {
1565 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1566 {
1567 if ( pSI && pSI->CountKashida() &&
1568 pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(),
1569 rInf.GetLen(), nSpaceAdd ) != STRING_LEN )
1570 nSpaceAdd = 0;
1571 else
1572 bNoHalfSpace = true;
1573 }
1574 }
1575
1576 // Thai Justification
1577 if ( SW_CTL == nActual && nSpaceAdd )
1578 {
1579 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
1580
1581 if ( LANGUAGE_THAI == aLang )
1582 {
1583 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray,
1584 pScrArray, rInf.GetIdx(),
1585 rInf.GetLen(),
1586 rInf.GetNumberOfBlanks(),
1587 rInf.GetSpace() );
1588
1589 // adding space to blanks is already done
1590 nSpaceAdd = 0;
1591 }
1592 }
1593 }
1594
1595 nScrPos = pScrArray[ 0 ];
1596
1597 if( bBullet )
1598 {
1599 // !!! HACK !!!
1600 // The Arabic layout engine requires some context of the string
1601 // which should be painted.
1602 xub_StrLen nCopyStart = rInf.GetIdx();
1603 if ( nCopyStart )
1604 --nCopyStart;
1605
1606 xub_StrLen nCopyLen = rInf.GetLen();
1607 if ( nCopyStart + nCopyLen < rInf.GetText().Len() )
1608 ++nCopyLen;
1609
1610 aStr = rInf.GetText().Copy( nCopyStart, nCopyLen );
1611 pStr = &aStr;
1612
1613 for( xub_StrLen i = 0; i < aStr.Len(); ++i )
1614 if( CH_BLANK == aStr.GetChar( i ) )
1615 aStr.SetChar( i, CH_BULLET );
1616 }
1617
1618 xub_StrLen nCnt = rInf.GetText().Len();
1619 if ( nCnt < rInf.GetIdx() )
1620 nCnt = 0;
1621 else
1622 nCnt = nCnt - rInf.GetIdx();
1623 nCnt = Min( nCnt, rInf.GetLen() );
1624 long nKernSum = rInf.GetKern();
1625 xub_Unicode cChPrev = rInf.GetText().GetChar( rInf.GetIdx() );
1626
1627 // Wenn es sich um ein singulaeres, unterstrichenes Space
1628 // im Blocksatz handelt, muessen wir zwei ausgeben:
1629 if ( ( nCnt == 1 ) && rInf.GetSpace() && ( cChPrev == CH_BLANK ) )
1630 {
1631 pKernArray[0] = rInf.GetWidth() +
1632 rInf.GetKern() +
1633 ( rInf.GetSpace() / SPACING_PRECISION_FACTOR );
1634
1635 if ( bSwitchL2R )
1636 rInf.GetFrm()->SwitchLTRtoRTL( aPos );
1637
1638 if ( bSwitchH2V )
1639 rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
1640
1641 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(),
1642 pKernArray, rInf.GetIdx(), 1 );
1643 if( bBullet )
1644 rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray,
1645 rInf.GetIdx() ? 1 : 0, 1 );
1646 }
1647 else
1648 {
1649 xub_Unicode nCh;
1650
1651 // Bei Pairkerning waechst der Printereinfluss auf die Positionierung
1652 sal_uInt16 nMul = 3;
1653
1654 if ( pPrtFont->GetKerning() )
1655 nMul = 1;
1656
1657 const sal_uInt16 nDiv = nMul+1;
1658
1659 // In nSpaceSum wird der durch Blocksatz auf die Spaces verteilte
1660 // Zwischenraum aufsummiert.
1661 // Die Spaces selbst werden im Normalfall in der Mitte des
1662 // Zwischenraums positioniert, deshalb die nSpace/2-Mimik.
1663 // Bei wortweiser Unterstreichung muessen sie am Anfang des
1664 // Zwischenraums stehen, damit dieser nicht unterstrichen wird.
1665 // Ein Space am Anfang oder am Ende des Textes muss allerdings
1666 // vor bzw. hinter den kompletten Zwischenraum gesetzt werden,
1667 // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen.
1668 long nSpaceSum = 0;
1669 // in word line mode and for Arabic, we disable the half space trick:
1670 const long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2;
1671 const long nOtherHalf = nSpaceAdd - nHalfSpace;
1672 if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
1673 nSpaceSum = nHalfSpace;
1674 for ( xub_StrLen i=1; i<nCnt; ++i,nKernSum += rInf.GetKern() )
1675 {
1676 nCh = rInf.GetText().GetChar( rInf.GetIdx() + i );
1677
1678 ASSERT( pScrArray, "Where is the screen array?" )
1679 long nScr;
1680 nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
1681
1682 // Wenn vor uns ein (Ex-)SPACE ist, positionieren wir uns optimal,
1683 // d.h. unseren rechten Rand auf die 100% Druckerposition,
1684 // sind wir sogar selbst ein Ex-SPACE, so positionieren wir uns
1685 // linksbuendig zur Druckerposition.
1686 if ( nCh == CH_BLANK )
1687 {
1688 #ifdef FONT_TEST_DEBUG
1689 lcl_Pos( 3, nScrPos, nScr, pKernArray[i-1], pKernArray[i] );
1690 #else
1691 nScrPos = pKernArray[i-1] + nScr;
1692 #endif
1693 if ( cChPrev == CH_BLANK )
1694 nSpaceSum += nOtherHalf;
1695 if ( i + 1 == nCnt )
1696 nSpaceSum += nSpaceAdd;
1697 else
1698 nSpaceSum += nHalfSpace;
1699 }
1700 else
1701 {
1702 if ( cChPrev == CH_BLANK )
1703 {
1704 #ifdef FONT_TEST_DEBUG
1705 lcl_Pos( 6, nScrPos, nScr, pKernArray[i-1], pKernArray[i] );
1706 #else
1707 nScrPos = pKernArray[i-1] + nScr;
1708 #endif
1709 // kein Pixel geht verloren:
1710 nSpaceSum += nOtherHalf;
1711 }
1712 else if ( cChPrev == '-' )
1713 #ifdef FONT_TEST_DEBUG
1714 lcl_Pos( 6, nScrPos, nScr, pKernArray[i-1], pKernArray[i] );
1715 #else
1716 nScrPos = pKernArray[i-1] + nScr;
1717 #endif
1718 else
1719 {
1720 #ifdef FONT_TEST_DEBUG
1721 lcl_Pos( 0, nScrPos, nScr, pKernArray[i-1], pKernArray[i] );
1722 #else
1723 nScrPos += nScr;
1724 nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
1725 #endif
1726 }
1727 }
1728 cChPrev = nCh;
1729 pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum;
1730 // In word line mode and for Arabic, we disabled the half space trick. If a portion
1731 // ends with a blank, the full nSpaceAdd value has been added to the character in
1732 // front of the blank. This leads to painting artifacts, therefore we remove the
1733 // nSpaceAdd value again:
1734 if ( (bNoHalfSpace || pPrtFont->IsWordLineMode()) && i+1 == nCnt && nCh == CH_BLANK )
1735 pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd;
1736 }
1737
1738 // the layout engine requires the total width of the output
1739 pKernArray[ rInf.GetLen() - 1 ] += nKernSum + nSpaceSum;
1740
1741 if( rInf.GetGreyWave() )
1742 {
1743 if( rInf.GetLen() )
1744 {
1745 long nHght = rInf.GetOut().LogicToPixel(
1746 pPrtFont->GetSize() ).Height();
1747 if( WRONG_SHOW_MIN < nHght )
1748 {
1749 if ( rInf.GetOut().GetConnectMetaFile() )
1750 rInf.GetOut().Push();
1751
1752 sal_uInt16 nWave =
1753 WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL :
1754 ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL :
1755 WAVE_FLAT );
1756 Color aCol( rInf.GetOut().GetLineColor() );
1757 sal_Bool bColSave = aCol != *pWaveCol;
1758 if ( bColSave )
1759 rInf.GetOut().SetLineColor( *pWaveCol );
1760
1761 Point aEnd;
1762 long nKernVal = pKernArray[ sal_uInt16( rInf.GetLen() - 1 ) ];
1763
1764 sal_uInt16 nDir = bBidiPor ?
1765 1800 :
1766 UnMapDirection(
1767 GetFont()->GetOrientation(),
1768 bSwitchH2V );
1769
1770 switch ( nDir )
1771 {
1772 case 0 :
1773 aEnd.X() = rInf.GetPos().X() + nKernVal;
1774 aEnd.Y() = rInf.GetPos().Y();
1775 break;
1776 case 900 :
1777 aEnd.X() = rInf.GetPos().X();
1778 aEnd.Y() = rInf.GetPos().Y() - nKernVal;
1779 break;
1780 case 1800 :
1781 aEnd.X() = rInf.GetPos().X() - nKernVal;
1782 aEnd.Y() = rInf.GetPos().Y();
1783 break;
1784 case 2700 :
1785 aEnd.X() = rInf.GetPos().X();
1786 aEnd.Y() = rInf.GetPos().Y() + nKernVal;
1787 break;
1788 }
1789
1790 Point aCurrPos( rInf.GetPos() );
1791
1792 if ( bSwitchL2R )
1793 {
1794 rInf.GetFrm()->SwitchLTRtoRTL( aCurrPos );
1795 rInf.GetFrm()->SwitchLTRtoRTL( aEnd );
1796 }
1797
1798 if ( bSwitchH2V )
1799 {
1800 rInf.GetFrm()->SwitchHorizontalToVertical( aCurrPos );
1801 rInf.GetFrm()->SwitchHorizontalToVertical( aEnd );
1802 }
1803 rInf.GetOut().DrawWaveLine( aCurrPos, aEnd, nWave );
1804
1805 if ( bColSave )
1806 rInf.GetOut().SetLineColor( aCol );
1807
1808 if ( rInf.GetOut().GetConnectMetaFile() )
1809 rInf.GetOut().Pop();
1810 }
1811 }
1812 }
1813 else if( !bSymbol && rInf.GetLen() )
1814 {
1815 // anything to do?
1816 if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
1817 {
1818 CalcLinePosData aCalcLinePosData(rInf, *GetFont(),
1819 nCnt, bSwitchH2V, bSwitchL2R,
1820 nHalfSpace, pKernArray, bBidiPor);
1821
1822 SwForbidden aForbidden;
1823 // draw line for smart tag data
1824 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() );
1825 // draw wave line for spell check errors
1826 // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict.
1827 // reason: some grammar errors can only be found if spelling errors are fixed,
1828 // therefore we don't want the user to miss a spelling error.
1829 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, pPrtFont->GetSize() );
1830 // draw wave line for grammar check errors
1831 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, pPrtFont->GetSize() );
1832 }
1833 }
1834
1835 xub_StrLen nOffs = 0;
1836 xub_StrLen nLen = rInf.GetLen();
1837 #ifdef COMING_SOON
1838 if( aPos.X() < rInf.GetLeft() )
1839 {
1840 while( nOffs < nLen &&
1841 aPos.X() + pKernArray[ nOffs ] < rInf.GetLeft() )
1842 ++nOffs;
1843 if( nOffs < nLen )
1844 {
1845 --nLen;
1846 while( nLen > nOffs &&
1847 aPos.X() + pKernArray[ nLen ] > rInf.GetRight() )
1848 --nLen;
1849 ++nLen;
1850 if( nOffs )
1851 --nOffs;
1852 }
1853 if( nOffs )
1854 {
1855 long nDiff = pKernArray[ nOffs - 1 ];
1856 aPos.X() += nDiff;
1857 for( xub_StrLen nX = nOffs; nX < nLen; ++nX )
1858 pKernArray[ nX ] -= nDiff;
1859 }
1860 }
1861 #endif
1862 if( nOffs < nLen )
1863 {
1864 // If we paint bullets instead of spaces, we use a copy of
1865 // the paragraph string. For the layout engine, the copy
1866 // of the string has to be an environment of the range which
1867 // is painted
1868 xub_StrLen nTmpIdx = bBullet ?
1869 ( rInf.GetIdx() ? 1 : 0 ) :
1870 rInf.GetIdx();
1871
1872 if ( bSwitchL2R )
1873 rInf.GetFrm()->SwitchLTRtoRTL( aPos );
1874
1875 if ( bSwitchH2V )
1876 rInf.GetFrm()->SwitchHorizontalToVertical( aPos );
1877
1878 rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray + nOffs,
1879 nTmpIdx + nOffs , nLen - nOffs );
1880 }
1881 }
1882 delete[] pScrArray;
1883 delete[] pKernArray;
1884 }
1885 }
1886
1887
1888 // Optimierung war fuer DrawText() ausgeschaltet
1889 #ifdef _MSC_VER
1890 #pragma optimize("",on)
1891 #endif
1892
1893
1894 /*************************************************************************
1895 *
1896 * Size SwFntObj::GetTextSize( const OutputDevice *pOut, const String &rTxt,
1897 * const sal_uInt16 nIdx, const sal_uInt16 nLen, const short nKern = 0 );
1898 *
1899 * Ersterstellung AMA 16. Dez. 94
1900 * Letzte Aenderung AMA 16. Dez. 94
1901 *
1902 * Beschreibung: ermittelt die TextSize (des Druckers)
1903 *
1904 *************************************************************************/
1905
GetTextSize(SwDrawTextInfo & rInf)1906 Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
1907 {
1908 Size aTxtSize;
1909 const xub_StrLen nLn = ( STRING_LEN != rInf.GetLen() ) ? rInf.GetLen() :
1910 rInf.GetText().Len();
1911
1912 // be sure to have the correct layout mode at the printer
1913 if ( pPrinter )
1914 {
1915 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
1916 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
1917 }
1918
1919 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1920 SW_CJK == rInf.GetFont()->GetActual() )
1921 {
1922 GETGRID( rInf.GetFrm()->FindPageFrm() )
1923 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
1924 {
1925 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1926 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
1927
1928 OutputDevice* pOutDev;
1929
1930 if ( pPrinter )
1931 {
1932 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1933 pPrinter->SetFont(*pPrtFont);
1934 pOutDev = pPrinter;
1935 }
1936 else
1937 pOutDev = rInf.GetpOut();
1938
1939 aTxtSize.Width() =
1940 pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn );
1941
1942 ASSERT( !rInf.GetShell() ||
1943 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ),
1944 "Leading values should be already calculated" )
1945 aTxtSize.Height() = pOutDev->GetTextHeight() +
1946 GetFontLeading( rInf.GetShell(), rInf.GetOut() );
1947
1948 long nWidthPerChar = aTxtSize.Width() / nLn;
1949
1950 const sal_uLong i = nWidthPerChar ?
1951 ( nWidthPerChar - 1 ) / nGridWidth + 1:
1952 1;
1953
1954 aTxtSize.Width() = i * nGridWidth * nLn;
1955 rInf.SetKanaDiff( 0 );
1956 return aTxtSize;
1957 }
1958 }
1959
1960 //for textgrid refactor
1961 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1962 SW_CJK == rInf.GetFont()->GetActual() )
1963 {
1964 GETGRID( rInf.GetFrm()->FindPageFrm() )
1965 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1966 {
1967 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
1968
1969 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1970 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
1971 if( SW_LATIN == rInf.GetFont()->GetActual() )
1972 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2;
1973 else
1974 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
1975 OutputDevice* pOutDev;
1976 if ( pPrinter )
1977 {
1978 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1979 pPrinter->SetFont(*pPrtFont);
1980 pOutDev = pPrinter;
1981 }
1982 else
1983 pOutDev = rInf.GetpOut();
1984 aTxtSize.Width() = pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn );
1985 aTxtSize.Height() = pOutDev->GetTextHeight() +
1986 GetFontLeading( rInf.GetShell(), rInf.GetOut() );
1987 aTxtSize.Width() += (nLn) * long( nGridWidthAdd );
1988 //if ( rInf.GetKern() && nLn )
1989 // aTxtSize.Width() += ( nLn ) * long( rInf.GetKern() );
1990
1991 rInf.SetKanaDiff( 0 );
1992 return aTxtSize;
1993 }
1994 }
1995
1996 const sal_Bool bCompress = rInf.GetKanaComp() && nLn &&
1997 rInf.GetFont() &&
1998 SW_CJK == rInf.GetFont()->GetActual() &&
1999 rInf.GetScriptInfo() &&
2000 rInf.GetScriptInfo()->CountCompChg() &&
2001 lcl_IsMonoSpaceFont( rInf.GetOut() );
2002
2003 ASSERT( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
2004 CountCompChg()), "Compression without info" );
2005
2006 // This is the part used e.g., for cursor travelling
2007 // See condition for DrawText or DrawTextArray (bDirectPrint)
2008 if ( pPrinter && pPrinter != rInf.GetpOut() )
2009 {
2010 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
2011 pPrinter->SetFont(*pPrtFont);
2012 aTxtSize.Width() = pPrinter->GetTextWidth( rInf.GetText(),
2013 rInf.GetIdx(), nLn );
2014 aTxtSize.Height() = pPrinter->GetTextHeight();
2015 sal_Int32 *pKernArray = new sal_Int32[nLn];
2016 CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
2017 if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
2018 rInf.GetOut().SetFont( *pScrFont );
2019 long nScrPos;
2020
2021 pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),nLn );
2022 if( bCompress )
2023 rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
2024 rInf.GetIdx(), nLn, rInf.GetKanaComp(),
2025 (sal_uInt16)aFont.GetSize().Height() ) );
2026 else
2027 rInf.SetKanaDiff( 0 );
2028
2029 if ( rInf.GetKanaDiff() )
2030 nScrPos = pKernArray[ nLn - 1 ];
2031 else
2032 {
2033 sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ];
2034 rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray,
2035 rInf.GetIdx(), rInf.GetLen() );
2036 nScrPos = pScrArray[ 0 ];
2037 xub_StrLen nCnt = rInf.GetText().Len();
2038 if ( nCnt < rInf.GetIdx() )
2039 nCnt=0;
2040 else
2041 nCnt = nCnt - rInf.GetIdx();
2042 nCnt = Min (nCnt, nLn);
2043 xub_Unicode nChPrev = rInf.GetText().GetChar( rInf.GetIdx() );
2044
2045 xub_Unicode nCh;
2046
2047 // Bei Pairkerning waechst der Printereinfluss auf die Positionierung
2048 sal_uInt16 nMul = 3;
2049 if ( pPrtFont->GetKerning() )
2050 nMul = 1;
2051 const sal_uInt16 nDiv = nMul+1;
2052 for( xub_StrLen i=1; i<nCnt; i++ )
2053 {
2054 nCh = rInf.GetText().GetChar( rInf.GetIdx() + i );
2055 long nScr;
2056 nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
2057 if ( nCh == CH_BLANK )
2058 nScrPos = pKernArray[i-1]+nScr;
2059 else
2060 {
2061 if ( nChPrev == CH_BLANK || nChPrev == '-' )
2062 nScrPos = pKernArray[i-1]+nScr;
2063 else
2064 {
2065 nScrPos += nScr;
2066 nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
2067 }
2068 }
2069 nChPrev = nCh;
2070 pKernArray[i-1] = nScrPos - nScr;
2071 }
2072 delete[] pScrArray;
2073 }
2074
2075 delete[] pKernArray;
2076 aTxtSize.Width() = nScrPos;
2077 }
2078 else
2079 {
2080 if( !pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) )
2081 rInf.GetOut().SetFont( *pPrtFont );
2082 if( bCompress )
2083 {
2084 sal_Int32 *pKernArray = new sal_Int32[nLn];
2085 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2086 rInf.GetIdx(), nLn );
2087 rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
2088 rInf.GetIdx(), nLn, rInf.GetKanaComp(),
2089 (sal_uInt16) aFont.GetSize().Height() ) );
2090 aTxtSize.Width() = pKernArray[ nLn - 1 ];
2091 delete[] pKernArray;
2092 }
2093 else
2094 {
2095 aTxtSize.Width() = rInf.GetOut().GetTextWidth( rInf.GetText(),
2096 rInf.GetIdx(), nLn );
2097 rInf.SetKanaDiff( 0 );
2098 }
2099
2100 aTxtSize.Height() = rInf.GetOut().GetTextHeight();
2101 }
2102
2103 if ( rInf.GetKern() && nLn )
2104 aTxtSize.Width() += ( nLn - 1 ) * long( rInf.GetKern() );
2105
2106 ASSERT( !rInf.GetShell() ||
2107 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ),
2108 "Leading values should be already calculated" )
2109 aTxtSize.Height() += GetFontLeading( rInf.GetShell(), rInf.GetOut() );
2110 return aTxtSize;
2111 }
2112
2113
GetCrsrOfst(SwDrawTextInfo & rInf)2114 xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf )
2115 {
2116 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
2117 const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR;
2118 long nKern = rInf.GetKern();
2119
2120 if( 0 != nSperren )
2121 nKern -= nSperren;
2122
2123 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ];
2124
2125 // be sure to have the correct layout mode at the printer
2126 if ( pPrinter )
2127 {
2128 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
2129 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
2130 pPrinter->GetTextArray( rInf.GetText(), pKernArray,
2131 rInf.GetIdx(), rInf.GetLen() );
2132 }
2133 else
2134 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2135 rInf.GetIdx(), rInf.GetLen() );
2136
2137 const SwScriptInfo* pSI = rInf.GetScriptInfo();
2138 if ( rInf.GetFont() && rInf.GetLen() )
2139 {
2140 const sal_uInt8 nActual = rInf.GetFont()->GetActual();
2141
2142 // Kana Compression
2143 if ( SW_CJK == nActual && rInf.GetKanaComp() &&
2144 pSI && pSI->CountCompChg() &&
2145 lcl_IsMonoSpaceFont( rInf.GetOut() ) )
2146 {
2147 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
2148 rInf.GetKanaComp(),
2149 (sal_uInt16) aFont.GetSize().Height() );
2150 }
2151
2152 // Asian Justification
2153 if ( SW_CJK == rInf.GetFont()->GetActual() )
2154 {
2155 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
2156
2157 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang )
2158 {
2159 long nSpaceSum = nSpaceAdd;
2160 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI )
2161 {
2162 pKernArray[ nI ] += nSpaceSum;
2163 nSpaceSum += nSpaceAdd;
2164 }
2165
2166 nSpaceAdd = 0;
2167 }
2168
2169 }
2170
2171 // Kashida Justification
2172 if ( SW_CTL == nActual && rInf.GetSpace() )
2173 {
2174 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
2175 {
2176 if ( pSI && pSI->CountKashida() &&
2177 pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(),
2178 nSpaceAdd ) != STRING_LEN )
2179 nSpaceAdd = 0;
2180 }
2181 }
2182
2183 // Thai Justification
2184 if ( SW_CTL == nActual && nSpaceAdd )
2185 {
2186 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
2187
2188 if ( LANGUAGE_THAI == aLang )
2189 {
2190 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0,
2191 rInf.GetIdx(), rInf.GetLen(),
2192 rInf.GetNumberOfBlanks(),
2193 rInf.GetSpace() );
2194
2195 // adding space to blanks is already done
2196 nSpaceAdd = 0;
2197 }
2198 }
2199 }
2200
2201 long nLeft = 0;
2202 long nRight = 0;
2203 xub_StrLen nCnt = 0;
2204 long nSpaceSum = 0;
2205 long nKernSum = 0;
2206
2207 if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() &&
2208 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
2209 {
2210 GETGRID( rInf.GetFrm()->FindPageFrm() )
2211 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2212 {
2213 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2214 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
2215
2216 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
2217
2218 sal_uLong i = nWidthPerChar ?
2219 ( nWidthPerChar - 1 ) / nGridWidth + 1:
2220 1;
2221
2222 nWidthPerChar = i * nGridWidth;
2223
2224 nCnt = (sal_uInt16)(rInf.GetOfst() / nWidthPerChar);
2225 if ( 2 * ( rInf.GetOfst() - nCnt * nWidthPerChar ) > nWidthPerChar )
2226 ++nCnt;
2227
2228 delete[] pKernArray;
2229 return nCnt;
2230 }
2231 }
2232
2233 //for textgrid refactor
2234 if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() &&
2235 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
2236 {
2237 GETGRID( rInf.GetFrm()->FindPageFrm() )
2238 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2239 {
2240
2241 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
2242
2243 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2244 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
2245 if( SW_LATIN == rInf.GetFont()->GetActual() )
2246 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2;
2247 else
2248 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
2249
2250 for(xub_StrLen j = 0; j < rInf.GetLen(); j++)
2251 {
2252 long nScr = pKernArray[ j ] + ( nSpaceAdd + nGridWidthAdd ) * ( j + 1 );
2253 if( nScr >= rInf.GetOfst())
2254 {
2255 nCnt = j;
2256 break;
2257 }
2258 }
2259 delete[] pKernArray;
2260 return nCnt;
2261 }
2262 }
2263
2264 sal_uInt16 nItrMode = i18n::CharacterIteratorMode::SKIPCELL;
2265 sal_Int32 nDone = 0;
2266 LanguageType aLang = LANGUAGE_NONE;
2267 bool bSkipCharacterCells = false;
2268 xub_StrLen nIdx = rInf.GetIdx();
2269 xub_StrLen nLastIdx = nIdx;
2270 const xub_StrLen nEnd = rInf.GetIdx() + rInf.GetLen();
2271
2272 // --> OD 2009-12-29 #i105901#
2273 // skip character cells for all script types
2274 if ( pBreakIt->GetBreakIter().is() )
2275 // <--
2276 {
2277 aLang = rInf.GetFont()->GetLanguage();
2278 bSkipCharacterCells = true;
2279 }
2280
2281 while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) )
2282 {
2283 if ( nSpaceAdd && CH_BLANK == rInf.GetText().GetChar( nIdx ) )
2284 nSpaceSum += nSpaceAdd;
2285
2286 // go to next character (cell).
2287 nLastIdx = nIdx;
2288
2289 if ( bSkipCharacterCells )
2290 {
2291 nIdx = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharacters( rInf.GetText(),
2292 nIdx, pBreakIt->GetLocale( aLang ), nItrMode, 1, nDone );
2293 if ( nIdx <= nLastIdx )
2294 break;
2295 }
2296 else
2297 ++nIdx;
2298
2299 nLeft = nRight;
2300 nRight = pKernArray[ nIdx - rInf.GetIdx() - 1 ] + nKernSum + nSpaceSum;
2301
2302 nKernSum += nKern;
2303 }
2304
2305 // step back if position is before the middle of the character
2306 // or if we do not want to go to the next character
2307 if ( nIdx > rInf.GetIdx() &&
2308 ( rInf.IsPosMatchesBounds() ||
2309 ( ( nRight > long( rInf.GetOfst() ) ) &&
2310 ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) )
2311 nCnt = nLastIdx - rInf.GetIdx(); // first half
2312 else
2313 nCnt = nIdx - rInf.GetIdx(); // second half
2314
2315 if ( pSI )
2316 rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) );
2317
2318 delete[] pKernArray;
2319 return nCnt;
2320 }
2321
2322
2323 /*************************************************************************
2324 |*
2325 |* SwFntAccess::SwFntAccess()
2326 |*
2327 |* Ersterstellung AMA 9. Nov. 94
2328 |* Letzte Aenderung AMA 9. Nov. 94
2329 |*
2330 |*************************************************************************/
2331
SwFntAccess(const void * & rMagic,sal_uInt16 & rIndex,const void * pOwn,ViewShell * pSh,sal_Bool bCheck)2332 SwFntAccess::SwFntAccess( const void* &rMagic,
2333 sal_uInt16 &rIndex, const void *pOwn, ViewShell *pSh,
2334 sal_Bool bCheck ) :
2335 SwCacheAccess( *pFntCache, rMagic, rIndex ),
2336 pShell( pSh )
2337 {
2338 // Der benutzte CTor von SwCacheAccess sucht anhand rMagic+rIndex im Cache
2339 if ( IsAvail() )
2340 {
2341 // Der schnellste Fall: ein bekannter Font ( rMagic ),
2342 // bei dem Drucker und Zoom nicht ueberprueft werden brauchen.
2343 if ( !bCheck )
2344 return;
2345
2346 // Hier ist zwar der Font bekannt, muss aber noch ueberprueft werden.
2347
2348 }
2349 else
2350 // Hier ist der Font nicht bekannt, muss also gesucht werden.
2351 bCheck = sal_False;
2352
2353
2354 {
2355 OutputDevice* pOut = 0;
2356 sal_uInt16 nZoom = USHRT_MAX;
2357
2358 // Get the reference device
2359 if ( pSh )
2360 {
2361 pOut = &pSh->GetRefDev();
2362 nZoom = pSh->GetViewOptions()->GetZoom();
2363 }
2364
2365 SwFntObj *pFntObj;
2366 if ( bCheck )
2367 {
2368 pFntObj = Get();
2369 if ( ( pFntObj->GetZoom( ) == nZoom ) &&
2370 ( pFntObj->pPrinter == pOut ) &&
2371 pFntObj->GetPropWidth() ==
2372 ((SwSubFont*)pOwn)->GetPropWidth() )
2373 return; // Die Ueberpruefung ergab: Drucker+Zoom okay.
2374 pFntObj->Unlock( ); // Vergiss dies Objekt, es wurde leider
2375 pObj = NULL; // eine Drucker/Zoomaenderung festgestellt.
2376 }
2377
2378 // Search by font comparison, quite expensive!
2379 // Look for same font and same printer
2380 pFntObj = pFntCache->First();
2381 while ( pFntObj && !( pFntObj->aFont == *(Font *)pOwn &&
2382 pFntObj->GetZoom() == nZoom &&
2383 pFntObj->GetPropWidth() ==
2384 ((SwSubFont*)pOwn)->GetPropWidth() &&
2385 ( !pFntObj->pPrinter || pFntObj->pPrinter == pOut ) ) )
2386 pFntObj = pFntCache->Next( pFntObj );
2387
2388 if( pFntObj && pFntObj->pPrinter != pOut )
2389 {
2390 // Wir haben zwar einen ohne Drucker gefunden, mal sehen, ob es
2391 // auch noch einen mit identischem Drucker gibt.
2392 SwFntObj *pTmpObj = pFntObj;
2393 while( pTmpObj && !( pTmpObj->aFont == *(Font *)pOwn &&
2394 pTmpObj->GetZoom()==nZoom && pTmpObj->pPrinter==pOut &&
2395 pTmpObj->GetPropWidth() ==
2396 ((SwSubFont*)pOwn)->GetPropWidth() ) )
2397 pTmpObj = pFntCache->Next( pTmpObj );
2398 if( pTmpObj )
2399 pFntObj = pTmpObj;
2400 }
2401
2402 if ( !pFntObj ) // Font has not been found, create one
2403 {
2404 // Das Objekt muss neu angelegt werden, deshalb muss der Owner ein
2405 // SwFont sein, spaeter wird als Owner die "MagicNumber" gehalten.
2406 SwCacheAccess::pOwner = pOwn;
2407 pFntObj = Get(); // hier wird via NewObj() angelegt und gelockt.
2408 ASSERT(pFntObj, "No Font, no Fun.");
2409 }
2410 else // Font has been found, so we lock it.
2411 {
2412 pFntObj->Lock();
2413 if( pFntObj->pPrinter != pOut ) // Falls bis dato kein Drucker bekannt
2414 {
2415 ASSERT( !pFntObj->pPrinter, "SwFntAccess: Printer Changed" );
2416 pFntObj->CreatePrtFont( *pOut );
2417 pFntObj->pPrinter = pOut;
2418 pFntObj->pScrFont = NULL;
2419 pFntObj->nGuessedLeading = USHRT_MAX;
2420 pFntObj->nExtLeading = USHRT_MAX;
2421 pFntObj->nPrtAscent = USHRT_MAX;
2422 pFntObj->nPrtHeight = USHRT_MAX;
2423 }
2424 pObj = pFntObj;
2425 }
2426
2427 // egal, ob neu oder gefunden, ab jetzt ist der Owner vom Objekt eine
2428 // MagicNumber und wird auch dem aufrufenden SwFont bekanntgegeben,
2429 // ebenso der Index fuer spaetere direkte Zugriffe
2430 rMagic = pFntObj->GetOwner();
2431 SwCacheAccess::pOwner = rMagic;
2432 rIndex = pFntObj->GetCachePos();
2433 }
2434 }
2435
NewObj()2436 SwCacheObj *SwFntAccess::NewObj( )
2437 {
2438 // Ein neuer Font, eine neue "MagicNumber".
2439 return new SwFntObj( *(SwSubFont *)pOwner, ++pMagicNo, pShell );
2440 }
2441
2442 extern xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt,
2443 const XubString& rOrigString,
2444 xub_StrLen nOfst,
2445 xub_StrLen nLen,
2446 xub_StrLen nIdx );
2447
GetTxtBreak(SwDrawTextInfo & rInf,long nTextWidth)2448 xub_StrLen SwFont::GetTxtBreak( SwDrawTextInfo& rInf, long nTextWidth )
2449 {
2450 ChgFnt( rInf.GetShell(), rInf.GetOut() );
2451
2452 const sal_Bool bCompress = rInf.GetKanaComp() && rInf.GetLen() &&
2453 SW_CJK == GetActual() &&
2454 rInf.GetScriptInfo() &&
2455 rInf.GetScriptInfo()->CountCompChg() &&
2456 lcl_IsMonoSpaceFont( rInf.GetOut() );
2457
2458 ASSERT( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
2459 CountCompChg()), "Compression without info" );
2460
2461 sal_uInt16 nTxtBreak = 0;
2462 long nKern = 0;
2463
2464 sal_uInt16 nLn = ( rInf.GetLen() == STRING_LEN ? rInf.GetText().Len()
2465 : rInf.GetLen() );
2466
2467 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() &&
2468 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
2469 {
2470 GETGRID( rInf.GetFrm()->FindPageFrm() )
2471 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2472 {
2473 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2474 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc);
2475
2476 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
2477 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2478 rInf.GetIdx(), rInf.GetLen() );
2479
2480 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
2481
2482 const sal_uLong i = nWidthPerChar ?
2483 ( nWidthPerChar - 1 ) / nGridWidth + 1:
2484 1;
2485
2486 nWidthPerChar = i * nGridWidth;
2487 long nCurrPos = nWidthPerChar;
2488
2489 while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos )
2490 {
2491 nCurrPos += nWidthPerChar;
2492 ++nTxtBreak;
2493 }
2494
2495 delete[] pKernArray;
2496 return nTxtBreak + rInf.GetIdx();
2497 }
2498 }
2499
2500 //for text grid enhancement
2501 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
2502 SW_CJK == rInf.GetFont()->GetActual() )
2503 {
2504 GETGRID( rInf.GetFrm()->FindPageFrm() )
2505 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2506 {
2507 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf );
2508
2509 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2510 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc);
2511 if( SW_LATIN == rInf.GetFont()->GetActual() )
2512 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2 ;
2513 else
2514 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight;
2515
2516 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()];
2517 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2518 rInf.GetIdx(), rInf.GetLen() );
2519 long nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd;
2520 while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos)
2521 {
2522 nTxtBreak++;
2523 nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd * ( nTxtBreak + 1 );
2524 }
2525 delete[] pKernArray;
2526 return nTxtBreak + rInf.GetIdx();
2527 }
2528 }
2529
2530 if( aSub[nActual].IsCapital() && nLn )
2531 nTxtBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(),
2532 rInf.GetScriptInfo(), rInf.GetText(), nTextWidth,0, rInf.GetIdx(),nLn );
2533 else
2534 {
2535 nKern = CheckKerning();
2536
2537 const XubString* pTmpText;
2538 XubString aTmpText;
2539 xub_StrLen nTmpIdx;
2540 xub_StrLen nTmpLen;
2541 bool bTextReplaced = false;
2542
2543 if ( !aSub[nActual].IsCaseMap() )
2544 {
2545 pTmpText = &rInf.GetText();
2546 nTmpIdx = rInf.GetIdx();
2547 nTmpLen = nLn;
2548 }
2549 else
2550 {
2551 const XubString aSnippet( rInf.GetText(), rInf.GetIdx(), nLn );
2552 aTmpText = aSub[nActual].CalcCaseMap( aSnippet );
2553 const bool bTitle = SVX_CASEMAP_TITEL == aSub[nActual].GetCaseMap() &&
2554 pBreakIt->GetBreakIter().is();
2555
2556 // Uaaaaahhhh!!! In title case mode, we would get wrong results
2557 if ( bTitle && nLn )
2558 {
2559 // check if rInf.GetIdx() is begin of word
2560 if ( !pBreakIt->GetBreakIter()->isBeginWord(
2561 rInf.GetText(), rInf.GetIdx(),
2562 pBreakIt->GetLocale( aSub[nActual].GetLanguage() ),
2563 i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
2564 {
2565 // In this case, the beginning of aTmpText is wrong.
2566 XubString aSnippetTmp( aSnippet, 0, 1 );
2567 aSnippetTmp = aSub[nActual].CalcCaseMap( aSnippetTmp );
2568 aTmpText.Erase( 0, aSnippetTmp.Len() );
2569 aTmpText.Insert( aSnippet.GetChar( 0 ), 0 );
2570 }
2571 }
2572
2573 pTmpText = &aTmpText;
2574 nTmpIdx = 0;
2575 nTmpLen = aTmpText.Len();
2576 bTextReplaced = true;
2577 }
2578
2579 if( rInf.GetHyphPos() )
2580 nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
2581 '-', *rInf.GetHyphPos(),
2582 nTmpIdx, nTmpLen, nKern );
2583 else
2584 nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
2585 nTmpIdx, nTmpLen, nKern );
2586
2587 if ( bTextReplaced && STRING_LEN != nTxtBreak )
2588 {
2589 if ( nTmpLen != nLn )
2590 nTxtBreak = lcl_CalcCaseMap( *this, rInf.GetText(),
2591 rInf.GetIdx(), nLn, nTxtBreak );
2592 else
2593 nTxtBreak = nTxtBreak + rInf.GetIdx();
2594 }
2595 }
2596
2597 if ( ! bCompress )
2598 return nTxtBreak;
2599
2600 nTxtBreak = nTxtBreak - rInf.GetIdx();
2601
2602 if( nTxtBreak < nLn )
2603 {
2604 if( !nTxtBreak && nLn )
2605 nLn = 1;
2606 else if( nLn > 2 * nTxtBreak )
2607 nLn = 2 * nTxtBreak;
2608 sal_Int32 *pKernArray = new sal_Int32[ nLn ];
2609 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2610 rInf.GetIdx(), nLn );
2611 if( rInf.GetScriptInfo()->Compress( pKernArray, rInf.GetIdx(), nLn,
2612 rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ) )
2613 {
2614 long nKernAdd = nKern;
2615 xub_StrLen nTmpBreak = nTxtBreak;
2616 if( nKern && nTxtBreak )
2617 nKern *= nTxtBreak - 1;
2618 while( nTxtBreak<nLn && nTextWidth >= pKernArray[nTxtBreak] +nKern )
2619 {
2620 nKern += nKernAdd;
2621 ++nTxtBreak;
2622 }
2623 if( rInf.GetHyphPos() )
2624 *rInf.GetHyphPos() += nTxtBreak - nTmpBreak; // It's not perfect
2625 }
2626 delete[] pKernArray;
2627 }
2628 nTxtBreak = nTxtBreak + rInf.GetIdx();
2629
2630 return nTxtBreak;
2631 }
2632
2633 extern Color aGlobalRetoucheColor;
2634
ApplyAutoColor(Font * pFont)2635 sal_Bool SwDrawTextInfo::ApplyAutoColor( Font* pFont )
2636 {
2637 const Font& rFnt = pFont ? *pFont : GetOut().GetFont();
2638 sal_Bool bPrt = GetShell() && ! GetShell()->GetWin();
2639 ColorData nNewColor = COL_BLACK;
2640 sal_Bool bChgFntColor = sal_False;
2641 sal_Bool bChgLineColor = sal_False;
2642
2643 if( bPrt && GetShell() && GetShell()->GetViewOptions()->IsBlackFont() )
2644 {
2645 if ( COL_BLACK != rFnt.GetColor().GetColor() )
2646 bChgFntColor = sal_True;
2647
2648 if ( (COL_BLACK != GetOut().GetLineColor().GetColor()) ||
2649 (COL_BLACK != GetOut().GetOverlineColor().GetColor()) )
2650 bChgLineColor = sal_True;
2651 }
2652 else
2653 {
2654 // FontColor has to be changed if:
2655 // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set
2656 // LineColor has to be changed if:
2657 // 1. IsAlwaysAutoColor is set
2658
2659 bChgLineColor = ! bPrt && GetShell() &&
2660 GetShell()->GetAccessibilityOptions()->IsAlwaysAutoColor();
2661
2662 bChgFntColor = COL_AUTO == rFnt.GetColor().GetColor() || bChgLineColor;
2663
2664 if ( bChgFntColor )
2665 {
2666 // check if current background has a user defined setting
2667 const Color* pCol = GetFont() ? GetFont()->GetBackColor() : NULL;
2668 if( ! pCol || COL_TRANSPARENT == pCol->GetColor() )
2669 {
2670 const SvxBrushItem* pItem;
2671 SwRect aOrigBackRect;
2672
2673 /// OD 21.08.2002
2674 /// consider, that [GetBackgroundBrush(...)] can set <pCol>
2675 /// - see implementation in /core/layout/paintfrm.cxx
2676 /// OD 21.08.2002 #99657#
2677 /// There is a user defined setting for the background, if there
2678 /// is a background brush and its color is *not* "no fill"/"auto fill".
2679 if( GetFrm()->GetBackgroundBrush( pItem, pCol, aOrigBackRect, sal_False ) )
2680 {
2681 if ( !pCol )
2682 {
2683 pCol = &pItem->GetColor();
2684 }
2685
2686 /// OD 30.08.2002 #99657#
2687 /// determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it.
2688 if ( pCol->GetColor() == COL_TRANSPARENT)
2689 pCol = NULL;
2690 }
2691 else
2692 pCol = NULL;
2693 }
2694
2695 // no user defined color at paragraph or font background
2696 if ( ! pCol )
2697 pCol = &aGlobalRetoucheColor;
2698
2699 if( GetShell() && GetShell()->GetWin() )
2700 {
2701 // here we determine the prefered window text color for painting
2702 const SwViewOption* pViewOption = GetShell()->GetViewOptions();
2703 if(pViewOption->IsPagePreview() &&
2704 !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews())
2705 nNewColor = COL_BLACK;
2706 else
2707 // we take the font color from the appearence page
2708 nNewColor = SwViewOption::GetFontColor().GetColor();
2709 }
2710
2711 // change painting color depending of dark/bright background
2712 Color aTmpColor( nNewColor );
2713 if ( pCol->IsDark() && aTmpColor.IsDark() )
2714 nNewColor = COL_WHITE;
2715 else if ( pCol->IsBright() && aTmpColor.IsBright() )
2716 nNewColor = COL_BLACK;
2717 }
2718 }
2719
2720 if ( bChgFntColor || bChgLineColor )
2721 {
2722 Color aNewColor( nNewColor );
2723
2724 if ( bChgFntColor )
2725 {
2726 if ( pFont && aNewColor != pFont->GetColor() )
2727 {
2728 // only set the new color at the font passed as argument
2729 pFont->SetColor( aNewColor );
2730 }
2731 else if ( aNewColor != GetOut().GetFont().GetColor() )
2732 {
2733 // set new font with new color at output device
2734 Font aFont( rFnt );
2735 aFont.SetColor( aNewColor );
2736 GetOut().SetFont( aFont );
2737 }
2738 }
2739
2740 // the underline and overline colors have to be set separately
2741 if ( bChgLineColor )
2742 {
2743 // get current font color or color set at output device
2744 aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor();
2745 if ( aNewColor != GetOut().GetLineColor() )
2746 GetOut().SetLineColor( aNewColor );
2747 if ( aNewColor != GetOut().GetOverlineColor() )
2748 GetOut().SetOverlineColor( aNewColor );
2749 }
2750
2751 return sal_True;
2752 }
2753
2754 return sal_False;
2755 }
2756
2757