Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "i18npool/mslangid.hxx"
31 : :
32 : : #include "rtl/tencinfo.h"
33 : : #include "rtl/logfile.hxx"
34 : :
35 : : #include "tools/debug.hxx"
36 : : #include "tools/poly.hxx"
37 : :
38 : : #include "basegfx/polygon/b2dpolygon.hxx"
39 : : #include "basegfx/polygon/b2dpolypolygon.hxx"
40 : : #include "basegfx/matrix/b2dhommatrix.hxx"
41 : :
42 : : #include "vcl/metric.hxx"
43 : : #include "vcl/metaact.hxx"
44 : : #include "vcl/gdimtf.hxx"
45 : : #include "vcl/virdev.hxx"
46 : : #include "vcl/print.hxx"
47 : : #include "vcl/event.hxx"
48 : : #include "vcl/window.hxx"
49 : : #include "vcl/svapp.hxx"
50 : : #include "vcl/bmpacc.hxx"
51 : : #include "vcl/outdev.hxx"
52 : : #include "vcl/edit.hxx"
53 : : // declare system types in sysdata.hxx
54 : : #include <svsys.h>
55 : : #include "vcl/sysdata.hxx"
56 : : #include "vcl/unohelp.hxx"
57 : : #include "vcl/controllayout.hxx"
58 : :
59 : : #include "salgdi.hxx"
60 : : #include "sallayout.hxx"
61 : : #include "svdata.hxx"
62 : : #include "impfont.hxx"
63 : : #include "outdata.hxx"
64 : : #include "outfont.hxx"
65 : : #include "outdev.h"
66 : : #include "textlayout.hxx"
67 : : #include "svids.hrc"
68 : : #include "window.h"
69 : :
70 : : #include "unotools/fontcvt.hxx"
71 : : #include "unotools/fontcfg.hxx"
72 : :
73 : : #include "osl/file.h"
74 : :
75 : : #ifdef ENABLE_GRAPHITE
76 : : #include "graphite_features.hxx"
77 : : #endif
78 : :
79 : : #include "pdfwriter_impl.hxx"
80 : :
81 : : #include "com/sun/star/beans/PropertyValues.hpp"
82 : : #include "com/sun/star/i18n/XBreakIterator.hpp"
83 : : #include "com/sun/star/i18n/WordType.hpp"
84 : : #include "com/sun/star/linguistic2/XLinguServiceManager.hpp"
85 : :
86 : : #if defined UNX
87 : : #define GLYPH_FONT_HEIGHT 128
88 : : #else
89 : : #define GLYPH_FONT_HEIGHT 256
90 : : #endif
91 : :
92 : : #include "sal/alloca.h"
93 : :
94 : : #include <cmath>
95 : : #include <cstring>
96 : :
97 : : #include <memory>
98 : : #include <algorithm>
99 : :
100 : :
101 : : // =======================================================================
102 : :
103 : : DBG_NAMEEX( OutputDevice )
104 : : DBG_NAMEEX( Font )
105 : :
106 : : // =======================================================================
107 : :
108 : : using namespace ::com::sun::star;
109 : : using namespace ::com::sun::star::uno;
110 : : using namespace ::rtl;
111 : : using namespace ::vcl;
112 : : using namespace ::utl;
113 : :
114 : : // =======================================================================
115 : :
116 : : #define TEXT_DRAW_ELLIPSIS (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
117 : :
118 : : // =======================================================================
119 : :
120 : : #define UNDERLINE_LAST UNDERLINE_BOLDWAVE
121 : : #define STRIKEOUT_LAST STRIKEOUT_X
122 : :
123 : : // =======================================================================
124 : :
125 : 243505 : static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
126 : : int nOrientation )
127 : : {
128 [ + + ][ + + ]: 243505 : if ( (nOrientation >= 0) && !(nOrientation % 900) )
129 : : {
130 [ - + ]: 9994 : if ( (nOrientation >= 3600) )
131 : 0 : nOrientation %= 3600;
132 : :
133 [ + - ]: 9994 : if ( nOrientation )
134 : : {
135 : 9994 : rX -= nOriginX;
136 : 9994 : rY -= nOriginY;
137 : :
138 [ + + ]: 9994 : if ( nOrientation == 900 )
139 : : {
140 : 2864 : long nTemp = rX;
141 : 2864 : rX = rY;
142 : 2864 : rY = -nTemp;
143 : : }
144 [ - + ]: 7130 : else if ( nOrientation == 1800 )
145 : : {
146 : 0 : rX = -rX;
147 : 0 : rY = -rY;
148 : : }
149 : : else /* ( nOrientation == 2700 ) */
150 : : {
151 : 7130 : long nTemp = rX;
152 : 7130 : rX = -rY;
153 : 7130 : rY = nTemp;
154 : : }
155 : :
156 : 9994 : rX += nOriginX;
157 : 9994 : rY += nOriginY;
158 : 9994 : }
159 : : }
160 : : else
161 : : {
162 : 233511 : double nRealOrientation = nOrientation*F_PI1800;
163 : 233511 : double nCos = cos( nRealOrientation );
164 : 233511 : double nSin = sin( nRealOrientation );
165 : :
166 : : // Translation...
167 : 233511 : long nX = rX-nOriginX;
168 : 233511 : long nY = rY-nOriginY;
169 : :
170 : : // Rotation...
171 : 233511 : rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
172 : 233511 : rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
173 : : }
174 : 243505 : }
175 : :
176 : : // =======================================================================
177 : :
178 : 8 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
179 : : {
180 : : // the currently selected logical font is no longer needed
181 [ - + ]: 8 : if ( mpFontEntry )
182 : : {
183 : 0 : mpFontCache->Release( mpFontEntry );
184 : 0 : mpFontEntry = NULL;
185 : : }
186 : :
187 : 8 : mbInitFont = true;
188 : 8 : mbNewFont = true;
189 : :
190 [ + - ]: 8 : if ( bNewFontLists )
191 : : {
192 [ + + ]: 8 : if ( mpGetDevFontList )
193 : : {
194 [ + - ]: 2 : delete mpGetDevFontList;
195 : 2 : mpGetDevFontList = NULL;
196 : : }
197 [ - + ]: 8 : if ( mpGetDevSizeList )
198 : : {
199 [ # # ]: 0 : delete mpGetDevSizeList;
200 : 0 : mpGetDevSizeList = NULL;
201 : : }
202 : :
203 : : // release all physically selected fonts on this device
204 [ + - ]: 8 : if( ImplGetGraphics() )
205 : 8 : mpGraphics->ReleaseFonts();
206 : : }
207 : :
208 [ - + ][ # # ]: 8 : if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
[ + - ]
209 : : {
210 : 8 : ImplSVData* pSVData = ImplGetSVData();
211 : :
212 [ + + ][ + - ]: 8 : if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
213 : 5 : mpFontCache->Invalidate();
214 : :
215 [ + - ]: 8 : if ( bNewFontLists )
216 : : {
217 : : // we need a graphics
218 [ + - ]: 8 : if ( ImplGetGraphics() )
219 : : {
220 [ + - ][ + + ]: 8 : if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
221 : 5 : mpFontList->Clear();
222 : :
223 [ - + ]: 8 : if( mpPDFWriter )
224 : : {
225 [ # # ][ # # ]: 0 : if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
226 [ # # ]: 0 : delete mpFontList;
227 [ # # ][ # # ]: 0 : if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
228 [ # # ]: 0 : delete mpFontCache;
229 : 0 : mpFontList = mpPDFWriter->filterDevFontList( pSVData->maGDIData.mpScreenFontList );
230 [ # # ]: 0 : mpFontCache = new ImplFontCache( sal_False );
231 : : }
232 : : else
233 : : {
234 [ - + ]: 8 : if( mpOutDevData )
235 : 0 : mpOutDevData->maDevFontSubst.Clear();
236 : 8 : mpGraphics->GetDevFontList( mpFontList );
237 : 8 : mpGraphics->GetDevFontSubstList( this );
238 : : }
239 : : }
240 : : }
241 : : }
242 : :
243 : : // also update child windows if needed
244 [ - + ]: 8 : if ( GetOutDevType() == OUTDEV_WINDOW )
245 : : {
246 : 0 : Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
247 [ # # ]: 0 : while ( pChild )
248 : : {
249 : 0 : pChild->ImplUpdateFontData( true );
250 : 0 : pChild = pChild->mpWindowImpl->mpNext;
251 : : }
252 : : }
253 : 8 : }
254 : :
255 : : // -----------------------------------------------------------------------
256 : :
257 : 0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
258 : : {
259 : 0 : ImplSVData* pSVData = ImplGetSVData();
260 : :
261 : : // update all windows
262 : 0 : Window* pFrame = pSVData->maWinData.mpFirstFrame;
263 [ # # ]: 0 : while ( pFrame )
264 : : {
265 : 0 : pFrame->ImplUpdateFontData( bNewFontLists );
266 : :
267 : 0 : Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
268 [ # # ]: 0 : while ( pSysWin )
269 : : {
270 : 0 : pSysWin->ImplUpdateFontData( bNewFontLists );
271 : 0 : pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
272 : : }
273 : :
274 : 0 : pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
275 : : }
276 : :
277 : : // update all virtual devices
278 : 0 : VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
279 [ # # ]: 0 : while ( pVirDev )
280 : : {
281 : 0 : pVirDev->ImplUpdateFontData( bNewFontLists );
282 : 0 : pVirDev = pVirDev->mpNext;
283 : : }
284 : :
285 : : // update all printers
286 : 0 : Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
287 [ # # ]: 0 : while ( pPrinter )
288 : : {
289 : 0 : pPrinter->ImplUpdateFontData( bNewFontLists );
290 : 0 : pPrinter = pPrinter->mpNext;
291 : : }
292 : :
293 : : // clear global font lists to have them updated
294 : 0 : pSVData->maGDIData.mpScreenFontCache->Invalidate();
295 [ # # ]: 0 : if ( bNewFontLists )
296 : : {
297 : 0 : pSVData->maGDIData.mpScreenFontList->Clear();
298 : 0 : pFrame = pSVData->maWinData.mpFirstFrame;
299 [ # # ]: 0 : if ( pFrame )
300 : : {
301 [ # # ]: 0 : if ( pFrame->ImplGetGraphics() )
302 : : // MT: Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler.
303 : 0 : ((OutputDevice*)pFrame)->mpGraphics->GetDevFontList( pFrame->mpWindowImpl->mpFrameData->mpFontList );
304 : : }
305 : : }
306 : 0 : }
307 : :
308 : : // =======================================================================
309 : :
310 : :
311 : : // =======================================================================
312 : :
313 : : // TODO: remove this method when the CWS-gfbfcfg dust has settled
314 : 158 : void ImplFreeOutDevFontData()
315 : 158 : {}
316 : :
317 : : // =======================================================================
318 : :
319 : 158 : void OutputDevice::BeginFontSubstitution()
320 : : {
321 : 158 : ImplSVData* pSVData = ImplGetSVData();
322 : 158 : pSVData->maGDIData.mbFontSubChanged = sal_False;
323 : 158 : }
324 : :
325 : : // -----------------------------------------------------------------------
326 : :
327 : 158 : void OutputDevice::EndFontSubstitution()
328 : : {
329 : 158 : ImplSVData* pSVData = ImplGetSVData();
330 [ - + ]: 158 : if ( pSVData->maGDIData.mbFontSubChanged )
331 : : {
332 [ # # ]: 0 : ImplUpdateAllFontData( false );
333 : :
334 [ # # ]: 0 : Application* pApp = GetpApp();
335 [ # # ]: 0 : DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
336 [ # # ]: 0 : pApp->DataChanged( aDCEvt );
337 [ # # ]: 0 : pApp->NotifyAllWindows( aDCEvt );
338 : 0 : pSVData->maGDIData.mbFontSubChanged = sal_False;
339 : : }
340 : 158 : }
341 : :
342 : : // -----------------------------------------------------------------------
343 : :
344 : 0 : void OutputDevice::AddFontSubstitute( const XubString& rFontName,
345 : : const XubString& rReplaceFontName,
346 : : sal_uInt16 nFlags )
347 : : {
348 : 0 : ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
349 [ # # ]: 0 : if( !rpSubst )
350 [ # # ]: 0 : rpSubst = new ImplDirectFontSubstitution();
351 : 0 : rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
352 : 0 : ImplGetSVData()->maGDIData.mbFontSubChanged = sal_True;
353 : 0 : }
354 : :
355 : : // -----------------------------------------------------------------------
356 : :
357 : 0 : void ImplDirectFontSubstitution::AddFontSubstitute( const String& rFontName,
358 : : const String& rSubstFontName, sal_uInt16 nFlags )
359 : : {
360 [ # # ]: 0 : maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
361 : 0 : }
362 : :
363 : : // -----------------------------------------------------------------------
364 : :
365 : 0 : ImplFontSubstEntry::ImplFontSubstEntry( const String& rFontName,
366 : : const String& rSubstFontName, sal_uInt16 nSubstFlags )
367 : : : maName( rFontName )
368 : : , maReplaceName( rSubstFontName )
369 [ # # ][ # # ]: 0 : , mnFlags( nSubstFlags )
[ # # ]
370 : : {
371 [ # # ]: 0 : maSearchName = rFontName;
372 [ # # ]: 0 : maSearchReplaceName = rSubstFontName;
373 [ # # ]: 0 : GetEnglishSearchFontName( maSearchName );
374 [ # # ]: 0 : GetEnglishSearchFontName( maSearchReplaceName );
375 : 0 : }
376 : :
377 : : // -----------------------------------------------------------------------
378 : :
379 : 0 : void OutputDevice::ImplAddDevFontSubstitute( const XubString& rFontName,
380 : : const XubString& rReplaceFontName,
381 : : sal_uInt16 nFlags )
382 : : {
383 : 0 : ImplInitOutDevData();
384 : 0 : mpOutDevData->maDevFontSubst.AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
385 : 0 : }
386 : :
387 : : // -----------------------------------------------------------------------
388 : :
389 : 0 : void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
390 : : {
391 : 0 : ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
392 [ # # ]: 0 : if( pSubst )
393 : 0 : pSubst->RemoveFontSubstitute( n );
394 : 0 : }
395 : :
396 : : // -----------------------------------------------------------------------
397 : :
398 : 0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
399 : : {
400 : 0 : FontSubstList::iterator it = maFontSubstList.begin();
401 [ # # ][ # # ]: 0 : for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
[ # # ][ # # ]
402 [ # # ]: 0 : if( it != maFontSubstList.end() )
403 [ # # ]: 0 : maFontSubstList.erase( it );
404 : 0 : }
405 : :
406 : : // -----------------------------------------------------------------------
407 : :
408 : 158 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
409 : : {
410 : 158 : const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
411 [ + - ]: 158 : if( !pSubst )
412 : 158 : return 0;
413 : 0 : int nCount = pSubst->GetFontSubstituteCount();
414 : 158 : return (sal_uInt16)nCount;
415 : : }
416 : :
417 : : // -----------------------------------------------------------------------
418 : :
419 : 49768 : bool ImplDirectFontSubstitution::FindFontSubstitute( String& rSubstName,
420 : : const String& rSearchName, sal_uInt16 nFlags ) const
421 : : {
422 : : // TODO: get rid of O(N) searches
423 : 49768 : FontSubstList::const_iterator it = maFontSubstList.begin();
424 [ - + ]: 49768 : for(; it != maFontSubstList.end(); ++it )
425 : : {
426 : 0 : const ImplFontSubstEntry& rEntry = *it;
427 [ # # ][ # # ]: 0 : if( ((rEntry.mnFlags & nFlags) || !nFlags)
[ # # ][ # # ]
428 [ # # ]: 0 : && (rEntry.maSearchName == rSearchName) )
429 : : {
430 [ # # ]: 0 : rSubstName = rEntry.maSearchReplaceName;
431 : 0 : return true;
432 : : }
433 : : }
434 : :
435 : 49768 : return false;
436 : : }
437 : :
438 : : // -----------------------------------------------------------------------
439 : :
440 : 184643 : static void ImplFontSubstitute( String& rFontName,
441 : : sal_uInt16 nFlags, ImplDirectFontSubstitution* pDevSpecific )
442 : : {
443 : : #ifdef DBG_UTIL
444 : : String aTempName = rFontName;
445 : : GetEnglishSearchFontName( aTempName );
446 : : DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
447 : : #endif
448 : :
449 [ + - ]: 184643 : String aSubstFontName;
450 : :
451 : : // apply user-configurable font replacement (eg, from the list in Tools->Options)
452 [ + - ]: 184643 : const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
453 [ - + ][ # # ]: 184643 : if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
[ # # ][ - + ]
454 : : {
455 [ # # ]: 0 : rFontName = aSubstFontName;
456 : : return;
457 : : }
458 : :
459 : : // apply device specific font replacement (e.g. to use printer builtin fonts)
460 [ + + ]: 184643 : if( !pDevSpecific )
461 : : return;
462 : :
463 [ + - ][ - + ]: 49768 : if( pDevSpecific->FindFontSubstitute( aSubstFontName, rFontName, nFlags ) )
464 : : {
465 [ # # ]: 49768 : rFontName = aSubstFontName;
466 : : return;
467 [ + - ][ + + ]: 184643 : }
468 : : }
469 : :
470 : : // -----------------------------------------------------------------------
471 : :
472 : 97781 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
473 : : sal_uLong nFlags, const OutputDevice* pOutDev )
474 : : {
475 : : OSL_TRACE( "OutputDevice::GetDefaultFont()" );
476 : :
477 : 97781 : com::sun::star::lang::Locale aLocale;
478 [ + + ][ - + ]: 97781 : if( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW )
[ + + ]
479 : : {
480 [ + - ][ + - ]: 738 : aLocale = Application::GetSettings().GetUILocale();
481 : : }
482 : : else
483 : : {
484 [ + - ]: 97043 : MsLangId::convertLanguageToLocale( eLang, aLocale );
485 : : }
486 : :
487 [ + - ]: 97781 : utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
488 [ + - ][ + - ]: 97781 : String aSearch = rDefaults.getUserInterfaceFont( aLocale ); // ensure a fallback
489 [ + - ][ + - ]: 97781 : String aDefault = rDefaults.getDefaultFont( aLocale, nType );
490 [ + + ]: 97781 : if( aDefault.Len() )
491 [ + - ]: 93209 : aSearch = aDefault;
492 : :
493 : 97781 : int nDefaultHeight = 12;
494 : :
495 [ + - ]: 97781 : Font aFont;
496 [ + - ]: 97781 : aFont.SetPitch( PITCH_VARIABLE );
497 : :
498 [ - + + + : 97781 : switch ( nType )
- + + - ]
499 : : {
500 : : case DEFAULTFONT_SANS_UNICODE:
501 : : case DEFAULTFONT_UI_SANS:
502 [ # # ]: 0 : aFont.SetFamily( FAMILY_SWISS );
503 : 0 : break;
504 : :
505 : : case DEFAULTFONT_SANS:
506 : : case DEFAULTFONT_LATIN_HEADING:
507 : : case DEFAULTFONT_LATIN_SPREADSHEET:
508 : : case DEFAULTFONT_LATIN_DISPLAY:
509 [ + - ]: 4483 : aFont.SetFamily( FAMILY_SWISS );
510 : 4483 : break;
511 : :
512 : : case DEFAULTFONT_SERIF:
513 : : case DEFAULTFONT_LATIN_TEXT:
514 : : case DEFAULTFONT_LATIN_PRESENTATION:
515 [ + - ]: 28623 : aFont.SetFamily( FAMILY_ROMAN );
516 : 28623 : break;
517 : :
518 : : case DEFAULTFONT_FIXED:
519 : : case DEFAULTFONT_LATIN_FIXED:
520 : : case DEFAULTFONT_UI_FIXED:
521 [ + - ]: 579 : aFont.SetPitch( PITCH_FIXED );
522 [ + - ]: 579 : aFont.SetFamily( FAMILY_MODERN );
523 : 579 : break;
524 : :
525 : : case DEFAULTFONT_SYMBOL:
526 [ # # ]: 0 : aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
527 : 0 : break;
528 : :
529 : : case DEFAULTFONT_CJK_TEXT:
530 : : case DEFAULTFONT_CJK_PRESENTATION:
531 : : case DEFAULTFONT_CJK_SPREADSHEET:
532 : : case DEFAULTFONT_CJK_HEADING:
533 : : case DEFAULTFONT_CJK_DISPLAY:
534 [ + - ]: 32048 : aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
535 : 32048 : break;
536 : :
537 : : case DEFAULTFONT_CTL_TEXT:
538 : : case DEFAULTFONT_CTL_PRESENTATION:
539 : : case DEFAULTFONT_CTL_SPREADSHEET:
540 : : case DEFAULTFONT_CTL_HEADING:
541 : : case DEFAULTFONT_CTL_DISPLAY:
542 [ + - ]: 32048 : aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
543 : 32048 : break;
544 : : }
545 : :
546 [ + - ]: 97781 : if ( aSearch.Len() )
547 : : {
548 [ + - ]: 97781 : aFont.SetHeight( nDefaultHeight );
549 [ + - ]: 97781 : aFont.SetWeight( WEIGHT_NORMAL );
550 [ + - ]: 97781 : aFont.SetLanguage( eLang );
551 : :
552 [ + - ][ + - ]: 97781 : if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
553 [ + - ][ + - ]: 97781 : aFont.SetCharSet( osl_getThreadTextEncoding() );
554 : :
555 : : // Should we only return available fonts on the given device
556 [ - + ]: 97781 : if ( pOutDev )
557 : : {
558 [ # # ]: 0 : pOutDev->ImplInitFontList();
559 : :
560 : : // Search Font in the FontList
561 [ # # ]: 0 : String aName;
562 [ # # ]: 0 : String aSearchName;
563 : 0 : xub_StrLen nIndex = 0;
564 [ # # ]: 0 : do
565 : : {
566 [ # # ][ # # ]: 0 : aSearchName = GetNextFontToken( aSearch, nIndex );
[ # # ]
567 [ # # ]: 0 : GetEnglishSearchFontName( aSearchName );
568 [ # # ]: 0 : ImplDevFontListData* pFontFamily = pOutDev->mpFontList->ImplFindBySearchName( aSearchName );
569 [ # # ]: 0 : if( pFontFamily )
570 : : {
571 [ # # ]: 0 : AddTokenFontName( aName, pFontFamily->GetFamilyName() );
572 [ # # ]: 0 : if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
573 : 0 : break;
574 : : }
575 : : }
576 : : while ( nIndex != STRING_NOTFOUND );
577 [ # # ][ # # ]: 0 : aFont.SetName( aName );
[ # # ][ # # ]
578 : : }
579 : :
580 : : // No Name, than set all names
581 [ + - ][ + - ]: 97781 : if ( !aFont.GetName().Len() )
582 : : {
583 [ + + ]: 97781 : if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
584 : : {
585 : :
586 [ + - ]: 97309 : if( !pOutDev )
587 [ + - ]: 97309 : pOutDev = (const OutputDevice *)ImplGetSVData()->mpDefaultWin;
588 [ + + ]: 97309 : if( !pOutDev )
589 : : {
590 : 735 : xub_StrLen nIndex = 0;
591 [ + - ][ + - ]: 735 : aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
[ + - ][ + - ]
592 : : }
593 : : else
594 : : {
595 [ + - ]: 96574 : pOutDev->ImplInitFontList();
596 : :
597 [ + - ][ + - ]: 96574 : aFont.SetName( aSearch );
598 : :
599 : : // convert to pixel height
600 [ + - ][ + - ]: 96574 : Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
601 [ - + ]: 96574 : if ( !aSize.Height() )
602 : : {
603 : : // use default pixel height only when logical height is zero
604 [ # # ][ # # ]: 0 : if ( aFont.GetHeight() )
605 : 0 : aSize.Height() = 1;
606 : : else
607 : 0 : aSize.Height() = (12*pOutDev->mnDPIY)/72;
608 : : }
609 : :
610 : : // use default width only when logical width is zero
611 [ + - ][ + - ]: 96574 : if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
[ - + ][ - + ]
612 : 0 : aSize.Width() = 1;
613 : :
614 : : // get the name of the first available font
615 : 96574 : float fExactHeight = static_cast<float>(aSize.Height());
616 [ + - ][ - + ]: 96574 : ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontList, aFont, aSize, fExactHeight, pOutDev->mpOutDevData ? &pOutDev->mpOutDevData->maDevFontSubst : NULL );
617 [ + - ]: 96574 : if (pEntry)
618 : : {
619 [ + - ]: 96574 : if( pEntry->maFontSelData.mpFontData )
620 [ + - ][ + - ]: 96574 : aFont.SetName( pEntry->maFontSelData.mpFontData->maName );
621 : : else
622 [ # # ][ # # ]: 96574 : aFont.SetName( pEntry->maFontSelData.maTargetName );
623 : : }
624 : : }
625 : : }
626 : : else
627 [ + - ][ + - ]: 472 : aFont.SetName( aSearch );
628 : : }
629 : : }
630 : :
631 : : #if OSL_DEBUG_LEVEL > 2
632 : : const char* s = "DEFAULTFONT_SANS_UNKNOWN";
633 : : switch ( nType )
634 : : {
635 : : case DEFAULTFONT_SANS_UNICODE: s = "DEFAULTFONT_SANS_UNICODE"; break;
636 : : case DEFAULTFONT_UI_SANS: s = "DEFAULTFONT_UI_SANS"; break;
637 : :
638 : : case DEFAULTFONT_SANS: s = "DEFAULTFONT_SANS"; break;
639 : : case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
640 : : case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
641 : : case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
642 : :
643 : : case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
644 : : case DEFAULTFONT_LATIN_TEXT: s = "DEFAULTFONT_LATIN_TEXT"; break;
645 : : case DEFAULTFONT_LATIN_PRESENTATION: s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
646 : :
647 : : case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
648 : : case DEFAULTFONT_LATIN_FIXED: s = "DEFAULTFONT_LATIN_FIXED"; break;
649 : : case DEFAULTFONT_UI_FIXED: s = "DEFAULTFONT_UI_FIXED"; break;
650 : :
651 : : case DEFAULTFONT_SYMBOL: s = "DEFAULTFONT_SYMBOL"; break;
652 : :
653 : : case DEFAULTFONT_CJK_TEXT: s = "DEFAULTFONT_CJK_TEXT"; break;
654 : : case DEFAULTFONT_CJK_PRESENTATION: s = "DEFAULTFONT_CJK_PRESENTATION"; break;
655 : : case DEFAULTFONT_CJK_SPREADSHEET: s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
656 : : case DEFAULTFONT_CJK_HEADING: s = "DEFAULTFONT_CJK_HEADING"; break;
657 : : case DEFAULTFONT_CJK_DISPLAY: s = "DEFAULTFONT_CJK_DISPLAY"; break;
658 : :
659 : : case DEFAULTFONT_CTL_TEXT: s = "DEFAULTFONT_CTL_TEXT"; break;
660 : : case DEFAULTFONT_CTL_PRESENTATION: s = "DEFAULTFONT_CTL_PRESENTATION"; break;
661 : : case DEFAULTFONT_CTL_SPREADSHEET: s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
662 : : case DEFAULTFONT_CTL_HEADING: s = "DEFAULTFONT_CTL_HEADING"; break;
663 : : case DEFAULTFONT_CTL_DISPLAY: s = "DEFAULTFONT_CTL_DISPLAY"; break;
664 : : }
665 : : fprintf( stderr, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
666 : : s, eLang, nFlags,
667 : : OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
668 : : );
669 : : #endif
670 : :
671 [ + - ][ + - ]: 97781 : return aFont;
672 : : }
673 : :
674 : : // =======================================================================
675 : :
676 : 0 : static unsigned ImplIsCJKFont( const String& rFontName )
677 : : {
678 : : // Test, if Fontname includes CJK characters --> In this case we
679 : : // mention that it is a CJK font
680 : 0 : const sal_Unicode* pStr = rFontName.GetBuffer();
681 [ # # ]: 0 : while ( *pStr )
682 : : {
683 : : // japanese
684 [ # # ][ # # ]: 0 : if ( ((*pStr >= 0x3040) && (*pStr <= 0x30FF)) ||
[ # # ][ # # ]
685 : : ((*pStr >= 0x3190) && (*pStr <= 0x319F)) )
686 : 0 : return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
687 : :
688 : : // korean
689 [ # # ][ # # ]: 0 : if ( ((*pStr >= 0xAC00) && (*pStr <= 0xD7AF)) ||
[ # # ][ # # ]
[ # # ][ # # ]
690 : : ((*pStr >= 0x3130) && (*pStr <= 0x318F)) ||
691 : : ((*pStr >= 0x1100) && (*pStr <= 0x11FF)) )
692 : 0 : return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
693 : :
694 : : // chinese
695 [ # # ][ # # ]: 0 : if ( ((*pStr >= 0x3400) && (*pStr <= 0x9FFF)) )
696 : 0 : return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
697 : :
698 : : // cjk
699 [ # # ][ # # ]: 0 : if ( ((*pStr >= 0x3000) && (*pStr <= 0xD7AF)) ||
[ # # ][ # # ]
700 : : ((*pStr >= 0xFF00) && (*pStr <= 0xFFEE)) )
701 : 0 : return IMPL_FONT_ATTR_CJK;
702 : :
703 : 0 : pStr++;
704 : : }
705 : :
706 : 0 : return 0;
707 : : }
708 : :
709 : : // -----------------------------------------------------------------------
710 : :
711 : 0 : static void ImplCalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth,
712 : : FontFamily eFamily, const FontNameAttr* pFontAttr )
713 : : {
714 [ # # ]: 0 : if ( eFamily != FAMILY_DONTKNOW )
715 : : {
716 [ # # ]: 0 : if ( eFamily == FAMILY_SWISS )
717 : 0 : rType |= IMPL_FONT_ATTR_SANSSERIF;
718 [ # # ]: 0 : else if ( eFamily == FAMILY_ROMAN )
719 : 0 : rType |= IMPL_FONT_ATTR_SERIF;
720 [ # # ]: 0 : else if ( eFamily == FAMILY_SCRIPT )
721 : 0 : rType |= IMPL_FONT_ATTR_SCRIPT;
722 [ # # ]: 0 : else if ( eFamily == FAMILY_MODERN )
723 : 0 : rType |= IMPL_FONT_ATTR_FIXED;
724 [ # # ]: 0 : else if ( eFamily == FAMILY_DECORATIVE )
725 : 0 : rType |= IMPL_FONT_ATTR_DECORATIVE;
726 : : }
727 : :
728 [ # # ]: 0 : if ( pFontAttr )
729 : : {
730 : 0 : rType |= pFontAttr->Type;
731 : :
732 [ # # ][ # # ]: 0 : if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
[ # # ]
733 : : (pFontAttr->Weight != WEIGHT_DONTKNOW) )
734 : 0 : rWeight = pFontAttr->Weight;
735 [ # # ][ # # ]: 0 : if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
[ # # ]
736 : : (pFontAttr->Width != WIDTH_DONTKNOW) )
737 : 0 : rWidth = pFontAttr->Width;
738 : : }
739 : 0 : }
740 : :
741 : : // =======================================================================
742 : :
743 : 58332 : PhysicalFontFace::PhysicalFontFace( const ImplDevFontAttributes& rDFA, int nMagic )
744 : : : ImplDevFontAttributes( rDFA ),
745 : : mnWidth(0),
746 : : mnHeight(0),
747 : : mnMagic( nMagic ),
748 : 58332 : mpNext( NULL )
749 : : {
750 : : // StarSymbol is a unicode font, but it still deserves the symbol flag
751 [ + + ]: 58332 : if( !mbSymbolFlag )
752 [ + - ][ + - ]: 114772 : if( 0 == GetFamilyName().CompareIgnoreCaseToAscii( "starsymbol", 10)
[ + + ][ + + ]
753 [ + - ]: 57386 : || 0 == GetFamilyName().CompareIgnoreCaseToAscii( "opensymbol", 10) )
754 : 272 : mbSymbolFlag = true;
755 : 58332 : }
756 : :
757 : : // -----------------------------------------------------------------------
758 : :
759 : 532044 : StringCompare PhysicalFontFace::CompareIgnoreSize( const PhysicalFontFace& rOther ) const
760 : : {
761 : : // compare their width, weight, italic and style name
762 [ - + ]: 532044 : if( meWidthType < rOther.meWidthType )
763 : 0 : return COMPARE_LESS;
764 [ - + ]: 532044 : else if( meWidthType > rOther.meWidthType )
765 : 0 : return COMPARE_GREATER;
766 : :
767 [ + + ]: 532044 : if( meWeight < rOther.meWeight )
768 : 7900 : return COMPARE_LESS;
769 [ + + ]: 524144 : else if( meWeight > rOther.meWeight )
770 : 294524 : return COMPARE_GREATER;
771 : :
772 [ + + ]: 229620 : if( meItalic < rOther.meItalic )
773 : 8750 : return COMPARE_LESS;
774 [ + + ]: 220870 : else if( meItalic > rOther.meItalic )
775 : 211264 : return COMPARE_GREATER;
776 : :
777 : 9606 : StringCompare eCompare = maName.CompareTo( rOther.maName );
778 : 532044 : return eCompare;
779 : : }
780 : :
781 : : // -----------------------------------------------------------------------
782 : :
783 : 329436 : StringCompare PhysicalFontFace::CompareWithSize( const PhysicalFontFace& rOther ) const
784 : : {
785 : 329436 : StringCompare eCompare = CompareIgnoreSize( rOther );
786 [ + + ]: 329436 : if( eCompare != COMPARE_EQUAL )
787 : 319830 : return eCompare;
788 : :
789 [ - + ]: 9606 : if( mnHeight < rOther.mnHeight )
790 : 0 : return COMPARE_LESS;
791 [ - + ]: 9606 : else if( mnHeight > rOther.mnHeight )
792 : 0 : return COMPARE_GREATER;
793 : :
794 [ - + ]: 9606 : if( mnWidth < rOther.mnWidth )
795 : 0 : return COMPARE_LESS;
796 [ - + ]: 9606 : else if( mnWidth > rOther.mnWidth )
797 : 0 : return COMPARE_GREATER;
798 : :
799 : 329436 : return COMPARE_EQUAL;
800 : : }
801 : :
802 : : // -----------------------------------------------------------------------
803 : :
804 : : struct FontMatchStatus
805 : : {
806 : : public:
807 : : int mnFaceMatch;
808 : : int mnHeightMatch;
809 : : int mnWidthMatch;
810 : : const xub_Unicode* mpTargetStyleName;
811 : : };
812 : :
813 : 28452 : bool PhysicalFontFace::IsBetterMatch( const FontSelectPattern& rFSD, FontMatchStatus& rStatus ) const
814 : : {
815 : 28452 : int nMatch = 0;
816 : :
817 : 28452 : const String& rFontName = rFSD.maTargetName;
818 [ + + ][ - + ]: 28452 : if( (rFontName == maName) || rFontName.EqualsIgnoreCaseAscii( maName ) )
[ + + ]
819 : 13920 : nMatch += 240000;
820 : :
821 [ - + # # ]: 28452 : if( rStatus.mpTargetStyleName
[ - + ]
822 : 0 : && maStyleName.EqualsIgnoreCaseAscii( rStatus.mpTargetStyleName ) )
823 : 0 : nMatch += 120000;
824 : :
825 [ + + ][ + + ]: 28452 : if( (rFSD.mePitch != PITCH_DONTKNOW) && (rFSD.mePitch == mePitch) )
826 : 17180 : nMatch += 20000;
827 : :
828 : : // prefer NORMAL font width
829 : : // TODO: change when the upper layers can tell their width preference
830 [ + + ]: 28452 : if( meWidthType == WIDTH_NORMAL )
831 : 28084 : nMatch += 400;
832 [ + - ][ - + ]: 368 : else if( (meWidthType == WIDTH_SEMI_EXPANDED) || (meWidthType == WIDTH_SEMI_CONDENSED) )
833 : 0 : nMatch += 300;
834 : :
835 [ + + ]: 28452 : if( rFSD.meWeight != WEIGHT_DONTKNOW )
836 : : {
837 : : // if not bold or requiring emboldening prefer light fonts to bold fonts
838 [ - + ]: 28140 : FontWeight ePatternWeight = rFSD.mbEmbolden ? WEIGHT_NORMAL : rFSD.meWeight;
839 : :
840 : 28140 : int nReqWeight = (int)ePatternWeight;
841 [ + + ]: 28140 : if ( ePatternWeight > WEIGHT_MEDIUM )
842 : 4632 : nReqWeight += 100;
843 : :
844 : 28140 : int nGivenWeight = (int)meWeight;
845 [ + + ]: 28140 : if( meWeight > WEIGHT_MEDIUM )
846 : 14070 : nGivenWeight += 100;
847 : :
848 : 28140 : int nWeightDiff = nReqWeight - nGivenWeight;
849 : :
850 [ + + ]: 28140 : if ( nWeightDiff == 0 )
851 : 14070 : nMatch += 1000;
852 [ + - ][ - + ]: 14070 : else if ( nWeightDiff == +1 || nWeightDiff == -1 )
853 : 0 : nMatch += 700;
854 [ + + ][ - + ]: 14070 : else if ( nWeightDiff < +50 && nWeightDiff > -50)
855 : 28140 : nMatch += 200;
856 : : }
857 : : else // requested weight == WEIGHT_DONTKNOW
858 : : {
859 : : // prefer NORMAL font weight
860 : : // TODO: change when the upper layers can tell their weight preference
861 [ + + ]: 312 : if( meWeight == WEIGHT_NORMAL )
862 : 156 : nMatch += 450;
863 [ - + ]: 156 : else if( meWeight == WEIGHT_MEDIUM )
864 : 0 : nMatch += 350;
865 [ + - ][ - + ]: 156 : else if( (meWeight == WEIGHT_SEMILIGHT) || (meWeight == WEIGHT_SEMIBOLD) )
866 : 0 : nMatch += 200;
867 [ - + ]: 156 : else if( meWeight == WEIGHT_LIGHT )
868 : 0 : nMatch += 150;
869 : : }
870 : :
871 : : // if requiring custom matrix to fake italic, prefer upright font
872 [ - + ]: 28452 : FontItalic ePatternItalic = rFSD.maItalicMatrix != ItalicMatrix() ? ITALIC_NONE : rFSD.meItalic;
873 : :
874 [ + + ]: 28452 : if ( ePatternItalic == ITALIC_NONE )
875 : : {
876 [ + + ]: 24852 : if( meItalic == ITALIC_NONE )
877 : 12426 : nMatch += 900;
878 : : }
879 : : else
880 : : {
881 [ + + ]: 3600 : if( ePatternItalic == meItalic )
882 : 1780 : nMatch += 900;
883 [ + + ]: 1820 : else if( meItalic != ITALIC_NONE )
884 : 20 : nMatch += 600;
885 : : }
886 : :
887 [ - + ]: 28452 : if( mbDevice )
888 : 0 : nMatch += 1;
889 : :
890 : 28452 : int nHeightMatch = 0;
891 : 28452 : int nWidthMatch = 0;
892 : :
893 [ + - ]: 28452 : if( IsScalable() )
894 : : {
895 [ + + ]: 28452 : if( rFSD.mnOrientation != 0 )
896 : 1016 : nMatch += 80;
897 [ + + ]: 27436 : else if( rFSD.mnWidth != 0 )
898 : 2552 : nMatch += 25;
899 : : else
900 : 24884 : nMatch += 5;
901 : : }
902 : : else
903 : : {
904 [ # # ]: 0 : if( rFSD.mnHeight == mnHeight )
905 : : {
906 : 0 : nMatch += 20;
907 [ # # ]: 0 : if( rFSD.mnWidth == mnWidth )
908 : 0 : nMatch += 10;
909 : : }
910 : : else
911 : : {
912 : : // for non-scalable fonts the size difference is very important
913 : : // prefer the smaller font face because of clipping/overlapping issues
914 : 0 : int nHeightDiff = (rFSD.mnHeight - mnHeight) * 1000;
915 [ # # ]: 0 : nHeightMatch = (nHeightDiff >= 0) ? -nHeightDiff : 100+nHeightDiff;
916 [ # # ]: 0 : if( rFSD.mnHeight )
917 : 0 : nHeightMatch /= rFSD.mnHeight;
918 : :
919 [ # # ][ # # ]: 0 : if( (rFSD.mnWidth != 0) && (mnWidth != 0) && (rFSD.mnWidth != mnWidth) )
[ # # ]
920 : : {
921 : 0 : int nWidthDiff = (rFSD.mnWidth - mnWidth) * 100;
922 : 0 : nWidthMatch = (nWidthDiff >= 0) ? -nWidthDiff : +nWidthDiff;
923 : : }
924 : : }
925 : : }
926 : :
927 [ + + ]: 28452 : if( rStatus.mnFaceMatch > nMatch )
928 : 18807 : return false;
929 [ + - ]: 9645 : else if( rStatus.mnFaceMatch < nMatch )
930 : : {
931 : 9645 : rStatus.mnFaceMatch = nMatch;
932 : 9645 : rStatus.mnHeightMatch = nHeightMatch;
933 : 9645 : rStatus.mnWidthMatch = nWidthMatch;
934 : 9645 : return true;
935 : : }
936 : :
937 : : // when two fonts are still competing prefer the
938 : : // one with the best matching height
939 [ # # ]: 0 : if( rStatus.mnHeightMatch > nHeightMatch )
940 : 0 : return false;
941 [ # # ]: 0 : else if( rStatus.mnHeightMatch < nHeightMatch )
942 : : {
943 : 0 : rStatus.mnHeightMatch = nHeightMatch;
944 : 0 : rStatus.mnWidthMatch = nWidthMatch;
945 : 0 : return true;
946 : : }
947 : :
948 [ # # ]: 0 : if( rStatus.mnWidthMatch > nWidthMatch )
949 : 0 : return false;
950 : :
951 : 0 : rStatus.mnWidthMatch = nWidthMatch;
952 : 28452 : return true;
953 : : }
954 : :
955 : : // =======================================================================
956 : :
957 : 9000 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
958 : : : maFontSelData( rFontSelData ),
959 : : maMetric( rFontSelData ),
960 : : mpConversion( NULL ),
961 : : mnRefCount( 1 ),
962 : : mnSetFontFlags( 0 ),
963 : : mnOwnOrientation( 0 ),
964 : : mnOrientation( 0 ),
965 : : mbInit( false ),
966 [ + - ]: 9000 : mpUnicodeFallbackList( NULL )
967 : : {
968 : 9000 : maFontSelData.mpFontEntry = this;
969 : 9000 : }
970 : :
971 : : // -----------------------------------------------------------------------
972 : :
973 [ + - ]: 6931 : ImplFontEntry::~ImplFontEntry()
974 : : {
975 [ + + ][ + - ]: 6931 : delete mpUnicodeFallbackList;
976 [ - + ]: 6931 : }
977 : :
978 : : // -----------------------------------------------------------------------
979 : :
980 : 13170 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
981 : : {
982 : : boost::hash<sal_UCS4> a;
983 : : boost::hash<int > b;
984 : 13170 : return a(rData.first) ^ b(rData.second);
985 : : }
986 : :
987 : 1062 : inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
988 : : {
989 [ + + ]: 1062 : if( !mpUnicodeFallbackList )
990 [ + - ][ + - ]: 558 : mpUnicodeFallbackList = new UnicodeFallbackList;
991 [ + - ][ + - ]: 1062 : (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
992 : 1062 : }
993 : :
994 : : // -----------------------------------------------------------------------
995 : :
996 : 13224 : inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, String* pFontName ) const
997 : : {
998 [ + + ]: 13224 : if( !mpUnicodeFallbackList )
999 : 1116 : return false;
1000 : :
1001 [ + - ][ + - ]: 12108 : UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
1002 [ + + ][ + - ]: 12108 : if( it == mpUnicodeFallbackList->end() )
1003 : 3516 : return false;
1004 : :
1005 [ + - ][ + - ]: 8592 : *pFontName = (*it).second;
1006 : 13224 : return true;
1007 : : }
1008 : :
1009 : : // -----------------------------------------------------------------------
1010 : :
1011 : 0 : inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
1012 : : {
1013 : : // DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
1014 [ # # ][ # # ]: 0 : UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
1015 : : // DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
1016 [ # # ][ # # ]: 0 : if( it == mpUnicodeFallbackList->end() )
1017 : 0 : return;
1018 [ # # ][ # # ]: 0 : if( (*it).second == rFontName )
[ # # ]
1019 [ # # ]: 0 : mpUnicodeFallbackList->erase( it );
1020 : : }
1021 : :
1022 : : // =======================================================================
1023 : :
1024 : 131426 : ImplDevFontListData::ImplDevFontListData( const String& rSearchName )
1025 : : : mpFirst( NULL ),
1026 : : maSearchName( rSearchName ),
1027 : : mnTypeFaces( 0 ),
1028 : : mnMatchType( 0 ),
1029 : : meMatchWeight( WEIGHT_DONTKNOW ),
1030 : : meMatchWidth( WIDTH_DONTKNOW ),
1031 : : meFamily( FAMILY_DONTKNOW ),
1032 : : mePitch( PITCH_DONTKNOW ),
1033 [ + - ][ + - ]: 131426 : mnMinQuality( -1 )
[ + - ]
1034 : 131426 : {}
1035 : :
1036 : : // -----------------------------------------------------------------------
1037 : :
1038 [ + - ][ + - ]: 120554 : ImplDevFontListData::~ImplDevFontListData()
[ + - ]
1039 : : {
1040 : : // release all physical font faces
1041 [ + + ]: 389614 : while( mpFirst )
1042 : : {
1043 : 269060 : PhysicalFontFace* pFace = mpFirst;
1044 : 269060 : mpFirst = pFace->GetNextFace();
1045 [ + - ][ + - ]: 269060 : delete pFace;
1046 : : }
1047 : 120554 : }
1048 : :
1049 : : // -----------------------------------------------------------------------
1050 : :
1051 : 301740 : bool ImplDevFontListData::AddFontFace( PhysicalFontFace* pNewData )
1052 : : {
1053 : 301740 : pNewData->mpNext = NULL;
1054 : :
1055 [ + + ]: 301740 : if( !mpFirst )
1056 : : {
1057 : 131426 : maName = pNewData->maName;
1058 : 131426 : maMapNames = pNewData->maMapNames;
1059 : 131426 : meFamily = pNewData->meFamily;
1060 : 131426 : mePitch = pNewData->mePitch;
1061 : 131426 : mnMinQuality = pNewData->mnQuality;
1062 : : }
1063 : : else
1064 : : {
1065 [ + + ]: 170314 : if( meFamily == FAMILY_DONTKNOW )
1066 : 168604 : meFamily = pNewData->meFamily;
1067 [ - + ]: 170314 : if( mePitch == PITCH_DONTKNOW )
1068 : 0 : mePitch = pNewData->mePitch;
1069 [ + + ]: 170314 : if( mnMinQuality > pNewData->mnQuality )
1070 : 67489 : mnMinQuality = pNewData->mnQuality;
1071 : : }
1072 : :
1073 : : // set attributes for attribute based font matching
1074 [ + - ]: 301740 : if( pNewData->IsScalable() )
1075 : 301740 : mnTypeFaces |= IMPL_DEVFONT_SCALABLE;
1076 : :
1077 [ + + ]: 301740 : if( pNewData->IsSymbolFont() )
1078 : 6315 : mnTypeFaces |= IMPL_DEVFONT_SYMBOL;
1079 : : else
1080 : 295425 : mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL;
1081 : :
1082 [ + - ]: 301740 : if( pNewData->meWeight != WEIGHT_DONTKNOW )
1083 : : {
1084 [ + + ]: 301740 : if( pNewData->meWeight >= WEIGHT_SEMIBOLD )
1085 : 117691 : mnTypeFaces |= IMPL_DEVFONT_BOLD;
1086 [ + + ]: 184049 : else if( pNewData->meWeight <= WEIGHT_SEMILIGHT )
1087 : 17164 : mnTypeFaces |= IMPL_DEVFONT_LIGHT;
1088 : : else
1089 : 166885 : mnTypeFaces |= IMPL_DEVFONT_NORMAL;
1090 : : }
1091 : :
1092 [ + + ]: 301740 : if( pNewData->meItalic == ITALIC_NONE )
1093 : 194718 : mnTypeFaces |= IMPL_DEVFONT_NONEITALIC;
1094 [ + + ][ + - ]: 107022 : else if( (pNewData->meItalic == ITALIC_NORMAL)
1095 : : || (pNewData->meItalic == ITALIC_OBLIQUE) )
1096 : 107022 : mnTypeFaces |= IMPL_DEVFONT_ITALIC;
1097 : :
1098 [ - + ][ # # ]: 301740 : if( (meMatchWeight == WEIGHT_DONTKNOW)
1099 : : || (meMatchWidth == WIDTH_DONTKNOW)
1100 : : || (mnMatchType == 0) )
1101 : : {
1102 : : // TODO: is it cheaper to calc matching attributes now or on demand?
1103 : : // calc matching attributes if other entries are already initialized
1104 : :
1105 : : // MT: Perform05: Do lazy, quite expensive, not needed in start-up!
1106 : : // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
1107 : : // InitMatchData( rFontSubst, maSearchName );
1108 : : // mbMatchData=true; // Somewhere else???
1109 : : }
1110 : :
1111 : : // reassign name (sharing saves memory)
1112 [ + - ]: 301740 : if( pNewData->maName == maName )
1113 : 301740 : pNewData->maName = maName;
1114 : :
1115 : : // insert new physical font face into linked list
1116 : : // TODO: get rid of linear search?
1117 : : PhysicalFontFace* pData;
1118 : 301740 : PhysicalFontFace** ppHere = &mpFirst;
1119 [ + + ]: 604920 : for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
1120 : : {
1121 : 329436 : StringCompare eComp = pNewData->CompareWithSize( *pData );
1122 [ + + ]: 329436 : if( eComp == COMPARE_GREATER )
1123 : 303180 : continue;
1124 [ + + ]: 26256 : if( eComp == COMPARE_LESS )
1125 : 16650 : break;
1126 : :
1127 : : // ignore duplicate if its quality is worse
1128 [ + + ]: 9606 : if( pNewData->mnQuality < pData->mnQuality )
1129 : 5562 : return false;
1130 : :
1131 : : // keep the device font if its quality is good enough
1132 [ + - ][ + - ]: 4044 : if( (pNewData->mnQuality == pData->mnQuality)
[ + - ]
1133 : 4044 : && (pData->mbDevice || !pNewData->mbDevice) )
1134 : 4044 : return false;
1135 : :
1136 : : // replace existing font face with a better one
1137 : 0 : pNewData->mpNext = pData->mpNext;
1138 : 0 : *ppHere = pNewData;
1139 [ # # ]: 0 : delete pData;
1140 : 0 : return true;
1141 : : }
1142 : :
1143 : : // insert into or append to list of physical font faces
1144 : 292134 : pNewData->mpNext = pData;
1145 : 292134 : *ppHere = pNewData;
1146 : 301740 : return true;
1147 : : }
1148 : :
1149 : : // -----------------------------------------------------------------------
1150 : :
1151 : : // get font attributes using the normalized font family name
1152 : 0 : void ImplDevFontListData::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
1153 : : const String& rSearchName )
1154 : : {
1155 [ # # ]: 0 : String aShortName;
1156 : : // get font attributes from the decorated font name
1157 : : rFontSubst.getMapName( rSearchName, aShortName, maMatchFamilyName,
1158 [ # # ]: 0 : meMatchWeight, meMatchWidth, mnMatchType );
1159 [ # # ][ # # ]: 0 : const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
1160 : : // eventually use the stripped name
1161 [ # # ]: 0 : if( !pFontAttr )
1162 [ # # ][ # # ]: 0 : if( aShortName != rSearchName )
1163 [ # # ][ # # ]: 0 : pFontAttr = rFontSubst.getSubstInfo( aShortName );
1164 : 0 : ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr );
1165 [ # # ]: 0 : mnMatchType |= ImplIsCJKFont( maName );
1166 : 0 : }
1167 : :
1168 : : // -----------------------------------------------------------------------
1169 : :
1170 : 9000 : PhysicalFontFace* ImplDevFontListData::FindBestFontFace( const FontSelectPattern& rFSD ) const
1171 : : {
1172 [ - + ]: 9000 : if( !mpFirst )
1173 : 0 : return NULL;
1174 [ + + ]: 9000 : if( !mpFirst->GetNextFace() )
1175 : 1887 : return mpFirst;
1176 : :
1177 : : // FontName+StyleName should map to FamilyName+StyleName
1178 : 7113 : const String& rSearchName = rFSD.maTargetName;
1179 : 7113 : const xub_Unicode* pTargetStyleName = NULL;
1180 [ + + ][ - + ]: 10878 : if( (rSearchName.Len() > maSearchName.Len())
[ - + ]
1181 [ + - ]: 3765 : && rSearchName.Equals( maSearchName, 0, maSearchName.Len() ) )
1182 : 0 : pTargetStyleName = rSearchName.GetBuffer() + maSearchName.Len() + 1;
1183 : :
1184 : : // linear search, TODO: improve?
1185 : 7113 : PhysicalFontFace* pFontFace = mpFirst;
1186 : 7113 : PhysicalFontFace* pBestFontFace = pFontFace;
1187 : 7113 : FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
1188 [ + + ]: 35565 : for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
1189 [ + - ][ + + ]: 28452 : if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
1190 : 9645 : pBestFontFace = pFontFace;
1191 : :
1192 : 9000 : return pBestFontFace;
1193 : : }
1194 : :
1195 : : // -----------------------------------------------------------------------
1196 : :
1197 : : // update device font list with unique font faces, with uniqueness
1198 : : // meaning different font attributes, but not different fonts sizes
1199 : 164160 : void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
1200 : : {
1201 : 164160 : PhysicalFontFace* pPrevFace = NULL;
1202 [ + + ]: 530928 : for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1203 : : {
1204 [ + + ][ + - ]: 366768 : if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
[ + - ]
1205 : 366768 : rDevFontList.Add( pFace );
1206 : 366768 : pPrevFace = pFace;
1207 : : }
1208 : 164160 : }
1209 : :
1210 : : // -----------------------------------------------------------------------
1211 : :
1212 : 1464 : void ImplDevFontListData::GetFontHeights( std::set<int>& rHeights ) const
1213 : : {
1214 : : // add all available font heights
1215 [ + + ]: 7320 : for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1216 [ + - ]: 5856 : rHeights.insert( pFace->GetHeight() );
1217 : 1464 : }
1218 : :
1219 : : // -----------------------------------------------------------------------
1220 : :
1221 : 110142 : void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList& rDevFontList,
1222 : : bool bScalable, bool bEmbeddable ) const
1223 : : {
1224 [ + + ]: 353550 : for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1225 : : {
1226 [ + - ][ - + ]: 243408 : if( bScalable && !pFace->IsScalable() )
[ - + ]
1227 : 0 : continue;
1228 [ - + ][ # # ]: 243408 : if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
[ # # ][ - + ]
1229 : 0 : continue;
1230 : :
1231 : 243408 : PhysicalFontFace* pClonedFace = pFace->Clone();
1232 : 243408 : rDevFontList.Add( pClonedFace );
1233 : : }
1234 : 110142 : }
1235 : :
1236 : : // =======================================================================
1237 : :
1238 : 2379 : ImplDevFontList::ImplDevFontList()
1239 : : : mbMatchData( false )
1240 : : , mbMapNames( false )
1241 : : , mpPreMatchHook( NULL )
1242 : : , mpFallbackHook( NULL )
1243 : : , mpFallbackList( NULL )
1244 [ + - ]: 2379 : , mnFallbackCount( -1 )
1245 : 2379 : {}
1246 : :
1247 : : // -----------------------------------------------------------------------
1248 : :
1249 : 2138 : ImplDevFontList::~ImplDevFontList()
1250 : : {
1251 [ + - ]: 2138 : Clear();
1252 [ - + ]: 4276 : }
1253 : :
1254 : : // -----------------------------------------------------------------------
1255 : :
1256 : 359 : void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
1257 : : {
1258 : 359 : mpPreMatchHook = pHook;
1259 : 359 : }
1260 : :
1261 : : // -----------------------------------------------------------------------
1262 : :
1263 : 359 : void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
1264 : : {
1265 : 359 : mpFallbackHook = pHook;
1266 : 359 : }
1267 : :
1268 : : // -----------------------------------------------------------------------
1269 : :
1270 : 4123 : void ImplDevFontList::Clear()
1271 : : {
1272 : : // remove fallback lists
1273 [ - + ]: 4123 : delete[] mpFallbackList;
1274 : 4123 : mpFallbackList = NULL;
1275 : 4123 : mnFallbackCount = -1;
1276 : :
1277 : : // clear all entries in the device font list
1278 [ + - ]: 4123 : DevFontList::iterator it = maDevFontList.begin();
1279 [ + - ][ + + ]: 124677 : for(; it != maDevFontList.end(); ++it )
1280 : : {
1281 [ + - ]: 120554 : ImplDevFontListData* pEntry = (*it).second;
1282 [ + - ][ + - ]: 120554 : delete pEntry;
1283 : : }
1284 : :
1285 [ + - ]: 4123 : maDevFontList.clear();
1286 : :
1287 : : // match data must be recalculated too
1288 : 4123 : mbMatchData = false;
1289 : 4123 : }
1290 : :
1291 : :
1292 : : // -----------------------------------------------------------------------
1293 : :
1294 : 0 : void ImplDevFontList::InitGenericGlyphFallback( void ) const
1295 : : {
1296 : : // normalized family names of fonts suited for glyph fallback
1297 : : // if a font is available related fonts can be ignored
1298 : : // TODO: implement dynamic lists
1299 : : static const char* aGlyphFallbackList[] = {
1300 : : // empty strings separate the names of unrelated fonts
1301 : : "eudc", "",
1302 : : "arialunicodems", "cyberbit", "code2000", "",
1303 : : "andalesansui", "",
1304 : : "starsymbol", "opensymbol", "",
1305 : : "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
1306 : : "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
1307 : : "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
1308 : : "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
1309 : : "shree", "mangal", "",
1310 : : "raavi", "shruti", "tunga", "",
1311 : : "latha", "gautami", "kartika", "vrinda", "",
1312 : : "shayyalmt", "naskmt", "scheherazade", "",
1313 : : "david", "nachlieli", "lucidagrande", "",
1314 : : "norasi", "angsanaupc", "",
1315 : : "khmerossystem", "",
1316 : : "muktinarrow", "",
1317 : : "phetsarathot", "",
1318 : : "padauk", "pinlonmyanmar", "",
1319 : : "iskoolapota", "lklug", "",
1320 : : 0
1321 : : };
1322 : :
1323 : 0 : bool bHasEudc = false;
1324 : 0 : int nMaxLevel = 0;
1325 : 0 : int nBestQuality = 0;
1326 : 0 : ImplDevFontListData** pFallbackList = NULL;
1327 : 0 : for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
1328 : : {
1329 : : // advance to next sub-list when end-of-sublist marker
1330 [ # # ]: 0 : if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
1331 : : {
1332 [ # # ]: 0 : if( nBestQuality > 0 )
1333 [ # # ]: 0 : if( ++nMaxLevel >= MAX_FALLBACK )
1334 : : break;
1335 [ # # ]: 0 : if( !ppNames[1] )
1336 : : break;
1337 : 0 : nBestQuality = 0;
1338 : 0 : continue;
1339 : : }
1340 : :
1341 : : // test if the glyph fallback candidate font is available and scalable
1342 [ # # ]: 0 : String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 );
1343 [ # # ]: 0 : ImplDevFontListData* pFallbackFont = FindFontFamily( aTokenName );
1344 [ # # ]: 0 : if( !pFallbackFont )
1345 : 0 : continue;
1346 [ # # ]: 0 : if( !pFallbackFont->IsScalable() )
1347 : 0 : continue;
1348 : :
1349 : : // keep the best font of the glyph fallback sub-list
1350 [ # # ]: 0 : if( nBestQuality < pFallbackFont->GetMinQuality() )
1351 : : {
1352 : 0 : nBestQuality = pFallbackFont->GetMinQuality();
1353 : : // store available glyph fallback fonts
1354 [ # # ]: 0 : if( !pFallbackList )
1355 [ # # ]: 0 : pFallbackList = new ImplDevFontListData*[ MAX_FALLBACK ];
1356 : 0 : pFallbackList[ nMaxLevel ] = pFallbackFont;
1357 [ # # ][ # # ]: 0 : if( !bHasEudc && !nMaxLevel )
1358 : 0 : bHasEudc = !strncmp( *ppNames, "eudc", 5 );
1359 : : }
1360 [ # # ][ # # ]: 0 : }
1361 : :
1362 : : #ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472#
1363 : : // sort the list of fonts for glyph fallback by quality (highest first)
1364 : : // #i33947# keep the EUDC font at the front of the list
1365 : : // an insertion sort is good enough for this short list
1366 : : const int nSortStart = bHasEudc ? 1 : 0;
1367 : : for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
1368 : : {
1369 : : ImplDevFontListData* pTestFont = pFallbackList[ i ];
1370 : : int nTestQuality = pTestFont->GetMinQuality();
1371 : : for( j = i; --j >= nSortStart; )
1372 : : if( nTestQuality > pFallbackList[j]->GetMinQuality() )
1373 : : pFallbackList[ j+1 ] = pFallbackList[ j ];
1374 : : else
1375 : : break;
1376 : : pFallbackList[ j+1 ] = pTestFont;
1377 : : }
1378 : : #endif
1379 : :
1380 : 0 : mnFallbackCount = nMaxLevel;
1381 : 0 : mpFallbackList = pFallbackList;
1382 : 0 : }
1383 : :
1384 : : // -----------------------------------------------------------------------
1385 : :
1386 : 9357 : ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
1387 : : rtl::OUString& rMissingCodes, int nFallbackLevel ) const
1388 : : {
1389 : 9357 : ImplDevFontListData* pFallbackData = NULL;
1390 : :
1391 : : // find a matching font candidate for platform specific glyph fallback
1392 [ + - ]: 9357 : if( mpFallbackHook )
1393 : : {
1394 : : // check cache for the first matching entry
1395 : : // to avoid calling the expensive fallback hook (#i83491#)
1396 : 9357 : sal_UCS4 cChar = 0;
1397 : 9357 : bool bCached = true;
1398 : 9357 : sal_Int32 nStrIndex = 0;
1399 [ + - ]: 9357 : while( nStrIndex < rMissingCodes.getLength() )
1400 : : {
1401 [ + - ]: 9357 : cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1402 [ + - ]: 9357 : bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
1403 : : // ignore entries which don't have a fallback
1404 [ + + ][ + - ]: 9357 : if( !bCached || (rFontSelData.maSearchName.Len() != 0) )
[ + - ]
1405 : 9357 : break;
1406 : : }
1407 : :
1408 [ + + ]: 9357 : if( bCached )
1409 : : {
1410 : : // there is a matching fallback in the cache
1411 : : // so update rMissingCodes with codepoints not yet resolved by this fallback
1412 : 5787 : int nRemainingLength = 0;
1413 : 5787 : sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
1414 [ + - ]: 5787 : String aFontName;
1415 [ + + ]: 6051 : while( nStrIndex < rMissingCodes.getLength() )
1416 : : {
1417 [ + - ]: 264 : cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1418 [ + - ]: 264 : bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
1419 [ + - ][ + - ]: 264 : if( !bCached || (rFontSelData.maSearchName != aFontName) )
[ - + ][ - + ]
1420 : 0 : pRemainingCodes[ nRemainingLength++ ] = cChar;
1421 : : }
1422 [ + - ][ + - ]: 5787 : rMissingCodes = rtl::OUString( pRemainingCodes, nRemainingLength );
1423 : : }
1424 : : else
1425 : : {
1426 : 3570 : rtl::OUString aOldMissingCodes = rMissingCodes;
1427 : : // call the hook to query the best matching glyph fallback font
1428 [ + - ][ + - ]: 3570 : if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
1429 : : // apply outdev3.cxx specific fontname normalization
1430 [ + - ]: 3570 : GetEnglishSearchFontName( rFontSelData.maSearchName );
1431 : : else
1432 [ # # ][ # # ]: 0 : rFontSelData.maSearchName = String();
[ # # ]
1433 : :
1434 : : //See fdo#32665 for an example. FreeSerif that has glyphs in normal
1435 : : //font, but not in the italic or bold version
1436 [ + - ][ - + ]: 3570 : bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
[ + - ]
1437 : :
1438 : : // cache the result even if there was no match, unless its from part of a font for which the properties need
1439 : : // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
1440 : : // for different input sizes, weights, etc. Basically the cache is way to naive
1441 [ + - ]: 3570 : if (!bSubSetOfFontRequiresPropertyFaking)
1442 : : {
1443 : 33 : for(;;)
1444 : : {
1445 [ + - ][ + + ]: 3603 : if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
1446 [ + - ]: 1062 : rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
1447 [ + + ]: 3603 : if( nStrIndex >= aOldMissingCodes.getLength() )
1448 : 3570 : break;
1449 [ + - ]: 33 : cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
1450 : : }
1451 [ + - ]: 3570 : if( rFontSelData.maSearchName.Len() != 0 )
1452 : : {
1453 : : // remove cache entries that were still not resolved
1454 [ - + ]: 3570 : for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1455 : : {
1456 [ # # ]: 0 : cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1457 [ # # ]: 0 : rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
1458 : : }
1459 : : }
1460 : 3570 : }
1461 : : }
1462 : :
1463 : : // find the matching device font
1464 [ + - ]: 9357 : if( rFontSelData.maSearchName.Len() != 0 )
1465 [ + - ]: 9357 : pFallbackData = FindFontFamily( rFontSelData.maSearchName );
1466 : : }
1467 : :
1468 : : // else find a matching font candidate for generic glyph fallback
1469 [ - + ]: 9357 : if( !pFallbackData )
1470 : : {
1471 : : // initialize font candidates for generic glyph fallback if needed
1472 [ # # ]: 0 : if( mnFallbackCount < 0 )
1473 : 0 : InitGenericGlyphFallback();
1474 : : // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
1475 [ # # ]: 0 : if( nFallbackLevel < mnFallbackCount )
1476 : 0 : pFallbackData = mpFallbackList[ nFallbackLevel ];
1477 : : }
1478 : :
1479 : 9357 : return pFallbackData;
1480 : : }
1481 : :
1482 : : // -----------------------------------------------------------------------
1483 : :
1484 : 301740 : void ImplDevFontList::Add( PhysicalFontFace* pNewData )
1485 : : {
1486 [ + - ]: 301740 : String aSearchName = pNewData->maName;
1487 [ + - ]: 301740 : GetEnglishSearchFontName( aSearchName );
1488 : :
1489 [ + - ]: 301740 : DevFontList::const_iterator it = maDevFontList.find( aSearchName );
1490 : 301740 : ImplDevFontListData* pFoundData = NULL;
1491 [ + + ][ + - ]: 301740 : if( it != maDevFontList.end() )
1492 [ + - ]: 170314 : pFoundData = (*it).second;
1493 : :
1494 [ + + ]: 301740 : if( !pFoundData )
1495 : : {
1496 [ + - ][ + - ]: 131426 : pFoundData = new ImplDevFontListData( aSearchName );
1497 [ + - ]: 131426 : maDevFontList[ aSearchName ] = pFoundData;
1498 : : }
1499 : :
1500 [ + - ]: 301740 : bool bKeepNewData = pFoundData->AddFontFace( pNewData );
1501 : :
1502 [ + + ]: 301740 : if( !bKeepNewData )
1503 [ + - ][ + - ]: 301740 : delete pNewData;
[ + - ]
1504 : 301740 : }
1505 : :
1506 : : // -----------------------------------------------------------------------
1507 : :
1508 : : // find the font from the normalized font family name
1509 : 488537 : ImplDevFontListData* ImplDevFontList::ImplFindBySearchName( const String& rSearchName ) const
1510 : : {
1511 : : #ifdef DEBUG
1512 : : String aTempName = rSearchName;
1513 : : GetEnglishSearchFontName( aTempName );
1514 : : DBG_ASSERT( aTempName == rSearchName, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
1515 : : #endif
1516 : :
1517 [ + - ]: 488537 : DevFontList::const_iterator it = maDevFontList.find( rSearchName );
1518 [ + - ][ + + ]: 488537 : if( it == maDevFontList.end() )
1519 : 311705 : return NULL;
1520 : :
1521 [ + - ]: 176832 : ImplDevFontListData* pFoundData = (*it).second;
1522 : 488537 : return pFoundData;
1523 : : }
1524 : :
1525 : : // -----------------------------------------------------------------------
1526 : :
1527 : 0 : ImplDevFontListData* ImplDevFontList::ImplFindByAliasName(const rtl::OUString& rSearchName,
1528 : : const rtl::OUString& rShortName) const
1529 : : {
1530 : : // short circuit for impossible font name alias
1531 [ # # ]: 0 : if (rSearchName.isEmpty())
1532 : 0 : return NULL;
1533 : :
1534 : : // short circuit if no alias names are available
1535 [ # # ]: 0 : if (!mbMapNames)
1536 : 0 : return NULL;
1537 : :
1538 : : // use the font's alias names to find the font
1539 : : // TODO: get rid of linear search
1540 [ # # ]: 0 : DevFontList::const_iterator it = maDevFontList.begin();
1541 [ # # ][ # # ]: 0 : while( it != maDevFontList.end() )
1542 : : {
1543 [ # # ]: 0 : ImplDevFontListData* pData = (*it).second;
1544 [ # # ]: 0 : if( !pData->maMapNames.Len() )
1545 : 0 : continue;
1546 : :
1547 : : // if one alias name matches we found a matching font
1548 : 0 : rtl::OUString aTempName;
1549 : 0 : xub_StrLen nIndex = 0;
1550 [ # # ]: 0 : do
1551 : : {
1552 [ # # ][ # # ]: 0 : aTempName = GetNextFontToken( pData->maMapNames, nIndex );
[ # # ]
1553 : : // Test, if the Font name match with one of the mapping names
1554 [ # # ][ # # ]: 0 : if ( (aTempName == rSearchName) || (aTempName == rShortName) )
[ # # ]
1555 : 0 : return pData;
1556 : : }
1557 : : while ( nIndex != STRING_NOTFOUND );
1558 [ # # ]: 0 : }
1559 : :
1560 : 0 : return NULL;
1561 : : }
1562 : :
1563 : : // -----------------------------------------------------------------------
1564 : :
1565 : 20240 : ImplDevFontListData* ImplDevFontList::FindFontFamily( const String& rFontName ) const
1566 : : {
1567 : : // normalize the font fomily name and
1568 [ + - ]: 20240 : String aName = rFontName;
1569 [ + - ]: 20240 : GetEnglishSearchFontName( aName );
1570 [ + - ]: 20240 : ImplDevFontListData* pFound = ImplFindBySearchName( aName );
1571 [ + - ]: 20240 : return pFound;
1572 : : }
1573 : :
1574 : : // -----------------------------------------------------------------------
1575 : :
1576 : 0 : ImplDevFontListData* ImplDevFontList::ImplFindByTokenNames(const rtl::OUString& rTokenStr) const
1577 : : {
1578 : 0 : ImplDevFontListData* pFoundData = NULL;
1579 : :
1580 : : // use normalized font name tokens to find the font
1581 [ # # ]: 0 : for( xub_StrLen nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
1582 : : {
1583 [ # # ][ # # ]: 0 : String aSearchName = GetNextFontToken( rTokenStr, nTokenPos );
[ # # ]
1584 [ # # ]: 0 : if( !aSearchName.Len() )
1585 : 0 : continue;
1586 [ # # ]: 0 : GetEnglishSearchFontName( aSearchName );
1587 [ # # ]: 0 : pFoundData = ImplFindBySearchName( aSearchName );
1588 [ # # ]: 0 : if( pFoundData )
1589 : : break;
1590 [ # # ]: 0 : }
[ # # # ]
1591 : :
1592 : 0 : return pFoundData;
1593 : : }
1594 : :
1595 : : // -----------------------------------------------------------------------
1596 : :
1597 : 18632 : ImplDevFontListData* ImplDevFontList::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
1598 : : {
1599 : 18632 : ImplDevFontListData* pFoundData = NULL;
1600 : :
1601 : : // use the font substitutions suggested by the FontNameAttr to find the font
1602 : 18632 : ::std::vector< String >::const_iterator it = rFontAttr.Substitutions.begin();
1603 [ + - ][ + - ]: 187303 : for(; it != rFontAttr.Substitutions.end(); ++it )
[ + - ]
1604 : : {
1605 [ + - ][ + - ]: 168671 : String aSearchName( *it );
1606 [ + - ]: 168671 : GetEnglishSearchFontName( aSearchName );
1607 : :
1608 [ + - ]: 168671 : pFoundData = ImplFindBySearchName( aSearchName );
1609 [ + + ]: 168671 : if( pFoundData )
1610 : 168671 : return pFoundData;
1611 [ + - ][ + + ]: 168671 : }
1612 : :
1613 : : // use known attributes from the configuration to find a matching substitute
1614 : 0 : const sal_uLong nSearchType = rFontAttr.Type;
1615 [ # # ]: 0 : if( nSearchType != 0 )
1616 : : {
1617 : 0 : const FontWeight eSearchWeight = rFontAttr.Weight;
1618 : 0 : const FontWidth eSearchWidth = rFontAttr.Width;
1619 : 0 : const FontItalic eSearchSlant = ITALIC_DONTKNOW;
1620 [ # # ]: 0 : const String aSearchName;
1621 : : pFoundData = ImplFindByAttributes( nSearchType,
1622 [ # # ][ # # ]: 0 : eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
1623 [ # # ]: 0 : if( pFoundData )
1624 [ # # ][ # # ]: 0 : return pFoundData;
1625 : : }
1626 : :
1627 : 18632 : return NULL;
1628 : : }
1629 : :
1630 : : // -----------------------------------------------------------------------
1631 : :
1632 : 0 : void ImplDevFontList::InitMatchData() const
1633 : : {
1634 : : // short circuit if already done
1635 [ # # ]: 0 : if( mbMatchData )
1636 : 0 : return;
1637 : 0 : mbMatchData = true;
1638 : :
1639 : : // calculate MatchData for all entries
1640 [ # # ]: 0 : const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
1641 : :
1642 [ # # ]: 0 : DevFontList::const_iterator it = maDevFontList.begin();
1643 [ # # ][ # # ]: 0 : for(; it != maDevFontList.end(); ++it )
1644 : : {
1645 [ # # ]: 0 : const String& rSearchName = (*it).first;
1646 [ # # ]: 0 : ImplDevFontListData* pEntry = (*it).second;
1647 : :
1648 [ # # ]: 0 : pEntry->InitMatchData( rFontSubst, rSearchName );
1649 : : }
1650 : : }
1651 : :
1652 : : // -----------------------------------------------------------------------
1653 : :
1654 : 0 : ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( sal_uLong nSearchType,
1655 : : FontWeight eSearchWeight, FontWidth eSearchWidth,
1656 : : FontItalic eSearchItalic, const rtl::OUString& rSearchFamilyName ) const
1657 : : {
1658 [ # # ][ # # ]: 0 : if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
1659 : 0 : nSearchType |= IMPL_FONT_ATTR_ITALIC;
1660 : :
1661 : : // don't bother to match attributes if the attributes aren't worth matching
1662 [ # # ][ # # ]: 0 : if( !nSearchType
[ # # ][ # # ]
[ # # ]
1663 : : && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
1664 : : && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
1665 : 0 : return NULL;
1666 : :
1667 [ # # ]: 0 : InitMatchData();
1668 : 0 : ImplDevFontListData* pFoundData = NULL;
1669 : :
1670 : : long nTestMatch;
1671 : 0 : long nBestMatch = 40000;
1672 : 0 : sal_uLong nBestType = 0;
1673 : :
1674 [ # # ]: 0 : DevFontList::const_iterator it = maDevFontList.begin();
1675 [ # # ][ # # ]: 0 : for(; it != maDevFontList.end(); ++it )
1676 : : {
1677 [ # # ]: 0 : ImplDevFontListData* pData = (*it).second;
1678 : :
1679 : : // Get all information about the matching font
1680 : 0 : sal_uLong nMatchType = pData->mnMatchType;
1681 : 0 : FontWeight eMatchWeight= pData->meMatchWeight;
1682 : 0 : FontWidth eMatchWidth = pData->meMatchWidth;
1683 : :
1684 : : // Calculate Match Value
1685 : : // 1000000000
1686 : : // 100000000
1687 : : // 10000000 CJK, CTL, None-Latin, Symbol
1688 : : // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
1689 : : // Titling, Capitals, Outline, Shadow
1690 : : // 100000 Match FamilyName, Serif, SansSerif, Italic,
1691 : : // Width, Weight
1692 : : // 10000 Scalable, Standard, Default,
1693 : : // full, Normal, Knownfont,
1694 : : // Otherstyle, +Special, +Decorative,
1695 : : // 1000 Typewriter, Rounded, Gothic, Schollbook
1696 : : // 100
1697 : 0 : nTestMatch = 0;
1698 : :
1699 : : // test CJK script attributes
1700 [ # # ]: 0 : if ( nSearchType & IMPL_FONT_ATTR_CJK )
1701 : : {
1702 : : // Matching language
1703 [ # # ]: 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
1704 : 0 : nTestMatch += 10000000*3;
1705 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_CJK )
1706 : 0 : nTestMatch += 10000000*2;
1707 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1708 : 0 : nTestMatch += 10000000;
1709 : : }
1710 [ # # ]: 0 : else if ( nMatchType & IMPL_FONT_ATTR_CJK )
1711 : 0 : nTestMatch -= 10000000;
1712 : :
1713 : : // test CTL script attributes
1714 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_CTL )
1715 : : {
1716 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_CTL )
1717 : 0 : nTestMatch += 10000000*2;
1718 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1719 : 0 : nTestMatch += 10000000;
1720 : : }
1721 [ # # ]: 0 : else if ( nMatchType & IMPL_FONT_ATTR_CTL )
1722 : 0 : nTestMatch -= 10000000;
1723 : :
1724 : : // test LATIN script attributes
1725 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
1726 : : {
1727 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
1728 : 0 : nTestMatch += 10000000*2;
1729 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1730 : 0 : nTestMatch += 10000000;
1731 : : }
1732 : :
1733 : : // test SYMBOL attributes
1734 [ # # ]: 0 : if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
1735 : : {
1736 [ # # ]: 0 : const String& rSearchName = it->first;
1737 : : // prefer some special known symbol fonts
1738 [ # # ][ # # ]: 0 : if ( rSearchName.EqualsAscii( "starsymbol" ) )
1739 : 0 : nTestMatch += 10000000*6+(10000*3);
1740 [ # # ][ # # ]: 0 : else if ( rSearchName.EqualsAscii( "opensymbol" ) )
1741 : 0 : nTestMatch += 10000000*6;
1742 [ # # ][ # # ]: 0 : else if ( rSearchName.EqualsAscii( "starbats" )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1743 [ # # ]: 0 : || rSearchName.EqualsAscii( "wingdings" )
1744 [ # # ]: 0 : || rSearchName.EqualsAscii( "monotypesorts" )
1745 [ # # ]: 0 : || rSearchName.EqualsAscii( "dingbats" )
1746 [ # # ]: 0 : || rSearchName.EqualsAscii( "zapfdingbats" ) )
1747 : 0 : nTestMatch += 10000000*5;
1748 [ # # ]: 0 : else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL )
1749 : 0 : nTestMatch += 10000000*4;
1750 : : else
1751 : : {
1752 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
1753 : 0 : nTestMatch += 10000000*2;
1754 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1755 : 0 : nTestMatch += 10000000;
1756 : : }
1757 : : }
1758 [ # # ]: 0 : else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL )
1759 : 0 : nTestMatch -= 10000000;
1760 [ # # ]: 0 : else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
1761 : 0 : nTestMatch -= 10000;
1762 : :
1763 : : // match stripped family name
1764 [ # # ][ # # ]: 0 : if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName.equals(pData->maMatchFamilyName)) )
[ # # ][ # # ]
[ # # # # ]
1765 : 0 : nTestMatch += 1000000*3;
1766 : :
1767 : : // match ALLSCRIPT? attribute
1768 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
1769 : : {
1770 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
1771 : 0 : nTestMatch += 1000000*2;
1772 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
1773 : : {
1774 [ # # ]: 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
1775 : 0 : nTestMatch += 1000000*2;
1776 [ # # ]: 0 : if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
1777 : 0 : nTestMatch -= 1000000;
1778 : : }
1779 : : }
1780 [ # # ]: 0 : else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
1781 : 0 : nTestMatch -= 1000000;
1782 : :
1783 : : // test MONOSPACE+TYPEWRITER attributes
1784 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_FIXED )
1785 : : {
1786 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_FIXED )
1787 : 0 : nTestMatch += 1000000*2;
1788 : : // a typewriter attribute is even better
1789 [ # # ]: 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
1790 : 0 : nTestMatch += 10000*2;
1791 : : }
1792 [ # # ]: 0 : else if( nMatchType & IMPL_FONT_ATTR_FIXED )
1793 : 0 : nTestMatch -= 1000000;
1794 : :
1795 : : // test SPECIAL attribute
1796 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
1797 : : {
1798 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
1799 : 0 : nTestMatch += 10000;
1800 [ # # ]: 0 : else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
1801 : : {
1802 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1803 : 0 : nTestMatch += 1000*2;
1804 [ # # ]: 0 : else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1805 : 0 : nTestMatch += 1000;
1806 : : }
1807 : : }
1808 [ # # ][ # # ]: 0 : else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
1809 : 0 : nTestMatch -= 1000000;
1810 : :
1811 : : // test DECORATIVE attribute
1812 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
1813 : : {
1814 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
1815 : 0 : nTestMatch += 10000;
1816 [ # # ]: 0 : else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
1817 : : {
1818 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1819 : 0 : nTestMatch += 1000*2;
1820 [ # # ]: 0 : else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1821 : 0 : nTestMatch += 1000;
1822 : : }
1823 : : }
1824 [ # # ]: 0 : else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
1825 : 0 : nTestMatch -= 1000000;
1826 : :
1827 : : // test TITLE+CAPITALS attributes
1828 [ # # ]: 0 : if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1829 : : {
1830 [ # # ]: 0 : if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1831 : 0 : nTestMatch += 1000000*2;
1832 [ # # ]: 0 : if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
1833 : 0 : nTestMatch += 1000000;
1834 [ # # ][ # # ]: 0 : else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))
1835 : : && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
1836 : 0 : nTestMatch += 1000000;
1837 : : }
1838 [ # # ]: 0 : else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1839 : 0 : nTestMatch -= 1000000;
1840 : :
1841 : : // test OUTLINE+SHADOW attributes
1842 [ # # ]: 0 : if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1843 : : {
1844 [ # # ]: 0 : if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1845 : 0 : nTestMatch += 1000000*2;
1846 [ # # ]: 0 : if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
1847 : 0 : nTestMatch += 1000000;
1848 [ # # ][ # # ]: 0 : else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW))
1849 : : && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
1850 : 0 : nTestMatch += 1000000;
1851 : : }
1852 [ # # ]: 0 : else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1853 : 0 : nTestMatch -= 1000000;
1854 : :
1855 : : // test font name substrings
1856 : : // TODO: calculate name matching score using e.g. Levenstein distance
1857 [ # # ]: 0 : if( (rSearchFamilyName.getLength() >= 4) && (pData->maMatchFamilyName.Len() >= 4)
[ # # # # ]
[ # # ][ # # ]
1858 [ # # ][ # # ]: 0 : && ((rSearchFamilyName.indexOf( pData->maMatchFamilyName ) != -1)
[ # # ]
1859 [ # # ][ # # ]: 0 : || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
[ # # ][ # # ]
[ # # ]
1860 : 0 : nTestMatch += 5000;
1861 : :
1862 : : // test SERIF attribute
1863 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_SERIF )
1864 : : {
1865 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1866 : 0 : nTestMatch += 1000000*2;
1867 [ # # ]: 0 : else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1868 : 0 : nTestMatch -= 1000000;
1869 : : }
1870 : :
1871 : : // test SANSERIF attribute
1872 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
1873 : : {
1874 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1875 : 0 : nTestMatch += 1000000;
1876 [ # # ]: 0 : else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
1877 : 0 : nTestMatch -= 1000000;
1878 : : }
1879 : :
1880 : : // test ITALIC attribute
1881 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_ITALIC )
1882 : : {
1883 [ # # ]: 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC )
1884 : 0 : nTestMatch += 1000000*3;
1885 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_ITALIC )
1886 : 0 : nTestMatch += 1000000;
1887 : : }
1888 [ # # ][ # # ]: 0 : else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT)
[ # # ]
1889 : : && ((nMatchType & IMPL_FONT_ATTR_ITALIC)
1890 : 0 : || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) )
1891 : 0 : nTestMatch -= 1000000*2;
1892 : :
1893 : : // test WIDTH attribute
1894 [ # # ][ # # ]: 0 : if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
1895 : : {
1896 [ # # ]: 0 : if( eSearchWidth < WIDTH_NORMAL )
1897 : : {
1898 [ # # ]: 0 : if( eSearchWidth == eMatchWidth )
1899 : 0 : nTestMatch += 1000000*3;
1900 [ # # ][ # # ]: 0 : else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
1901 : 0 : nTestMatch += 1000000;
1902 : : }
1903 : : else
1904 : : {
1905 [ # # ]: 0 : if( eSearchWidth == eMatchWidth )
1906 : 0 : nTestMatch += 1000000*3;
1907 [ # # ]: 0 : else if( eMatchWidth > WIDTH_NORMAL )
1908 : 0 : nTestMatch += 1000000;
1909 : : }
1910 : : }
1911 [ # # ][ # # ]: 0 : else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
1912 : 0 : nTestMatch -= 1000000;
1913 : :
1914 : : // test WEIGHT attribute
1915 [ # # ][ # # ]: 0 : if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) )
[ # # ]
1916 : : {
1917 [ # # ]: 0 : if( eSearchWeight < WEIGHT_NORMAL )
1918 : : {
1919 [ # # ]: 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT )
1920 : 0 : nTestMatch += 1000000;
1921 [ # # ][ # # ]: 0 : if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
1922 : 0 : nTestMatch += 1000000;
1923 : : }
1924 : : else
1925 : : {
1926 [ # # ]: 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD )
1927 : 0 : nTestMatch += 1000000;
1928 [ # # ]: 0 : if( eMatchWeight > WEIGHT_BOLD )
1929 : 0 : nTestMatch += 1000000;
1930 : : }
1931 : : }
1932 [ # # ][ # # ]: 0 : else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM))
[ # # ][ # # ]
1933 : 0 : || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) )
1934 : 0 : nTestMatch -= 1000000;
1935 : :
1936 : : // prefer scalable fonts
1937 [ # # ]: 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE )
1938 : 0 : nTestMatch += 10000*4;
1939 : : else
1940 : 0 : nTestMatch -= 10000*4;
1941 : :
1942 : : // test STANDARD+DEFAULT+FULL+NORMAL attributes
1943 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_STANDARD )
1944 : 0 : nTestMatch += 10000*2;
1945 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
1946 : 0 : nTestMatch += 10000;
1947 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1948 : 0 : nTestMatch += 10000;
1949 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_NORMAL )
1950 : 0 : nTestMatch += 10000;
1951 : :
1952 : : // test OTHERSTYLE attribute
1953 [ # # ]: 0 : if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 )
1954 : : {
1955 : 0 : nTestMatch -= 10000;
1956 : : }
1957 : :
1958 : : // test ROUNDED attribute
1959 [ # # ]: 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
1960 : 0 : nTestMatch += 1000;
1961 : :
1962 : : // test TYPEWRITER attribute
1963 [ # # ]: 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
1964 : 0 : nTestMatch += 1000;
1965 : :
1966 : : // test GOTHIC attribute
1967 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
1968 : : {
1969 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
1970 : 0 : nTestMatch += 1000*3;
1971 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1972 : 0 : nTestMatch += 1000*2;
1973 : : }
1974 : :
1975 : : // test SCHOOLBOOK attribute
1976 [ # # ]: 0 : if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
1977 : : {
1978 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
1979 : 0 : nTestMatch += 1000*3;
1980 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1981 : 0 : nTestMatch += 1000*2;
1982 : : }
1983 : :
1984 : : // compare with best matching font yet
1985 [ # # ]: 0 : if ( nTestMatch > nBestMatch )
1986 : : {
1987 : 0 : pFoundData = pData;
1988 : 0 : nBestMatch = nTestMatch;
1989 : 0 : nBestType = nMatchType;
1990 : : }
1991 [ # # ]: 0 : else if( nTestMatch == nBestMatch )
1992 : : {
1993 : : // some fonts are more suitable defaults
1994 [ # # ]: 0 : if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
1995 : : {
1996 : 0 : pFoundData = pData;
1997 : 0 : nBestType = nMatchType;
1998 : : }
1999 [ # # ][ # # ]: 0 : else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
2000 : 0 : !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
2001 : : {
2002 : 0 : pFoundData = pData;
2003 : 0 : nBestType = nMatchType;
2004 : : }
2005 : : }
2006 : : }
2007 : :
2008 : 0 : return pFoundData;
2009 : : }
2010 : :
2011 : : // -----------------------------------------------------------------------
2012 : :
2013 : 0 : ImplDevFontListData* ImplDevFontList::FindDefaultFont() const
2014 : : {
2015 : : // try to find one of the default fonts of the
2016 : : // UNICODE, SANSSERIF, SERIF or FIXED default font lists
2017 [ # # ]: 0 : const DefaultFontConfiguration& rDefaults = DefaultFontConfiguration::get();
2018 [ # # ]: 0 : com::sun::star::lang::Locale aLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2019 [ # # ][ # # ]: 0 : String aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS_UNICODE );
2020 [ # # ][ # # ]: 0 : ImplDevFontListData* pFoundData = ImplFindByTokenNames( aFontname );
2021 [ # # ]: 0 : if( pFoundData )
2022 : 0 : return pFoundData;
2023 : :
2024 [ # # ][ # # ]: 0 : aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS );
2025 [ # # ][ # # ]: 0 : pFoundData = ImplFindByTokenNames( aFontname );
2026 [ # # ]: 0 : if( pFoundData )
2027 : 0 : return pFoundData;
2028 : :
2029 [ # # ][ # # ]: 0 : aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SERIF );
2030 [ # # ][ # # ]: 0 : pFoundData = ImplFindByTokenNames( aFontname );
2031 [ # # ]: 0 : if( pFoundData )
2032 : 0 : return pFoundData;
2033 : :
2034 [ # # ][ # # ]: 0 : aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_FIXED );
2035 [ # # ][ # # ]: 0 : pFoundData = ImplFindByTokenNames( aFontname );
2036 [ # # ]: 0 : if( pFoundData )
2037 : 0 : return pFoundData;
2038 : :
2039 : : // now try to find a reasonable non-symbol font
2040 : :
2041 [ # # ]: 0 : InitMatchData();
2042 : :
2043 [ # # ]: 0 : DevFontList::const_iterator it = maDevFontList.begin();
2044 [ # # ][ # # ]: 0 : for(; it != maDevFontList.end(); ++it )
2045 : : {
2046 [ # # ]: 0 : ImplDevFontListData* pData = (*it).second;
2047 [ # # ]: 0 : if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL )
2048 : 0 : continue;
2049 : 0 : pFoundData = pData;
2050 [ # # ]: 0 : if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
2051 : 0 : break;
2052 : : }
2053 [ # # ]: 0 : if( pFoundData )
2054 : 0 : return pFoundData;
2055 : :
2056 : : // finding any font is better than finding no font at all
2057 [ # # ]: 0 : it = maDevFontList.begin();
2058 [ # # ][ # # ]: 0 : if( it != maDevFontList.end() )
2059 [ # # ]: 0 : pFoundData = (*it).second;
2060 : :
2061 [ # # ]: 0 : return pFoundData;
2062 : : }
2063 : :
2064 : : // -----------------------------------------------------------------------
2065 : :
2066 : 2004 : ImplDevFontList* ImplDevFontList::Clone( bool bScalable, bool bEmbeddable ) const
2067 : : {
2068 [ + - ][ + - ]: 2004 : ImplDevFontList* pClonedList = new ImplDevFontList;
2069 : : // pClonedList->mbMatchData = mbMatchData;
2070 : 2004 : pClonedList->mbMapNames = mbMapNames;
2071 : 2004 : pClonedList->mpPreMatchHook = mpPreMatchHook;
2072 : 2004 : pClonedList->mpFallbackHook = mpFallbackHook;
2073 : :
2074 : : // TODO: clone the config-font attributes too?
2075 : 2004 : pClonedList->mbMatchData = false;
2076 : :
2077 [ + - ]: 2004 : DevFontList::const_iterator it = maDevFontList.begin();
2078 [ + - ][ + + ]: 112146 : for(; it != maDevFontList.end(); ++it )
2079 : : {
2080 [ + - ]: 110142 : const ImplDevFontListData* pFontFace = (*it).second;
2081 [ + - ]: 110142 : pFontFace->UpdateCloneFontList( *pClonedList, bScalable, bEmbeddable );
2082 : : }
2083 : :
2084 : 2004 : return pClonedList;
2085 : : }
2086 : :
2087 : : // -----------------------------------------------------------------------
2088 : :
2089 : 2925 : ImplGetDevFontList* ImplDevFontList::GetDevFontList() const
2090 : : {
2091 [ + - ][ + - ]: 2925 : ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
2092 : :
2093 [ + - ]: 2925 : DevFontList::const_iterator it = maDevFontList.begin();
2094 [ + - ][ + + ]: 167085 : for(; it != maDevFontList.end(); ++it )
2095 : : {
2096 [ + - ]: 164160 : const ImplDevFontListData* pFontFamily = (*it).second;
2097 [ + - ]: 164160 : pFontFamily->UpdateDevFontList( *pGetDevFontList );
2098 : : }
2099 : :
2100 : 2925 : return pGetDevFontList;
2101 : : }
2102 : :
2103 : : // -----------------------------------------------------------------------
2104 : :
2105 : 1481 : ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) const
2106 : : {
2107 [ + - ]: 1481 : ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
2108 : :
2109 : 1481 : ImplDevFontListData* pFontFamily = FindFontFamily( rFontName );
2110 [ + + ]: 1481 : if( pFontFamily != NULL )
2111 : : {
2112 [ + - ]: 1464 : std::set<int> rHeights;
2113 [ + - ]: 1464 : pFontFamily->GetFontHeights( rHeights );
2114 : :
2115 : 1464 : std::set<int>::const_iterator it = rHeights.begin();
2116 [ # # ][ + - ]: 1464 : for(; it != rHeights.begin(); ++it )
[ - + ]
2117 [ # # ][ # # ]: 1464 : pGetDevSizeList->Add( *it );
2118 : : }
2119 : :
2120 : 1481 : return pGetDevSizeList;
2121 : : }
2122 : :
2123 : 841765 : FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont,
2124 : : const String& rSearchName, const Size& rSize, float fExactHeight )
2125 : : : maSearchName( rSearchName )
2126 : 841765 : , mnWidth( rSize.Width() )
2127 : 841765 : , mnHeight( rSize.Height() )
2128 : : , mfExactHeight( fExactHeight)
2129 [ + - ]: 841765 : , mnOrientation( rFont.GetOrientation() )
2130 [ + - ]: 841765 : , meLanguage( rFont.GetLanguage() )
2131 [ + - ]: 841765 : , mbVertical( rFont.IsVertical() )
2132 : : , mbNonAntialiased( false )
2133 [ + - ][ + - ]: 1683530 : , mbEmbolden( false )
2134 : : {
2135 [ + - ]: 841765 : maTargetName = maName;
2136 : :
2137 [ + - ]: 841765 : rFont.GetFontAttributes( *this );
2138 : :
2139 : : // normalize orientation between 0 and 3600
2140 [ - + ]: 841765 : if( 3600 <= (unsigned)mnOrientation )
2141 : : {
2142 [ # # ]: 0 : if( mnOrientation >= 0 )
2143 : 0 : mnOrientation %= 3600;
2144 : : else
2145 : 0 : mnOrientation = 3600 - (-mnOrientation % 3600);
2146 : : }
2147 : :
2148 : : // normalize width and height
2149 [ + + ]: 841765 : if( mnHeight < 0 )
2150 : 304 : mnHeight = -mnHeight;
2151 [ + + ]: 841765 : if( mnWidth < 0 )
2152 : 450 : mnWidth = -mnWidth;
2153 : 841765 : }
2154 : :
2155 : 841765 : FontSelectPattern::FontSelectPattern( const Font& rFont,
2156 : : const String& rSearchName, const Size& rSize, float fExactHeight)
2157 : : : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
2158 : : , mpFontData( NULL )
2159 : 841765 : , mpFontEntry( NULL )
2160 : : {
2161 : 841765 : }
2162 : :
2163 : : // NOTE: this ctor is still used on Windows. Do not remove.
2164 : 0 : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
2165 : : const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
2166 : : : ImplFontAttributes( rFontData )
2167 : 0 : , mnWidth( rSize.Width() )
2168 : 0 : , mnHeight( rSize.Height() )
2169 : : , mfExactHeight( fExactHeight )
2170 : : , mnOrientation( nOrientation )
2171 : : , meLanguage( 0 )
2172 : : , mbVertical( bVertical )
2173 : : , mbNonAntialiased( false )
2174 [ # # ][ # # ]: 0 : , mbEmbolden( false )
2175 : : {
2176 [ # # ][ # # ]: 0 : maTargetName = maSearchName = maName;
2177 : : // NOTE: no normalization for width/height/orientation
2178 : 0 : }
2179 : :
2180 : 0 : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
2181 : : const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
2182 : : : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
2183 : : , mpFontData( &rFontData )
2184 : 0 : , mpFontEntry( NULL )
2185 : : {
2186 : 0 : }
2187 : :
2188 : 91172 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
2189 : : {
2190 : 91172 : static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
2191 : 91172 : }
2192 : :
2193 : : // =======================================================================
2194 : :
2195 : 619457 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
2196 : : {
2197 : 619457 : return rFSD.hashCode();
2198 : : }
2199 : :
2200 : 619457 : size_t FontSelectPatternAttributes::hashCode() const
2201 : : {
2202 : : // TODO: does it pay off to improve this hash function?
2203 : : static FontNameHash aFontNameHash;
2204 : 619457 : size_t nHash = aFontNameHash( maSearchName );
2205 : : #ifdef ENABLE_GRAPHITE
2206 : : // check for features and generate a unique hash if necessary
2207 [ - + ]: 619457 : if (maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2208 : : != STRING_NOTFOUND)
2209 : : {
2210 : 0 : nHash = aFontNameHash( maTargetName );
2211 : : }
2212 : : #endif
2213 : 619457 : nHash += 11 * mnHeight;
2214 : 619457 : nHash += 19 * meWeight;
2215 : 619457 : nHash += 29 * meItalic;
2216 : 619457 : nHash += 37 * mnOrientation;
2217 : 619457 : nHash += 41 * meLanguage;
2218 [ - + ]: 619457 : if( mbVertical )
2219 : 0 : nHash += 53;
2220 : 619457 : return nHash;
2221 : : }
2222 : :
2223 : 188552 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
2224 : : {
2225 [ + + ]: 188552 : if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
2226 : 49268 : return false;
2227 : :
2228 [ - + ]: 139284 : if (maTargetName != rOther.maTargetName)
2229 : 0 : return false;
2230 : :
2231 [ - + ]: 139284 : if (maSearchName != rOther.maSearchName)
2232 : 0 : return false;
2233 : :
2234 [ + + ]: 139284 : if (mnWidth != rOther.mnWidth)
2235 : 40155 : return false;
2236 : :
2237 [ + + ]: 99129 : if (mnHeight != rOther.mnHeight)
2238 : 6252 : return false;
2239 : :
2240 [ + + ]: 92877 : if (mfExactHeight != rOther.mfExactHeight)
2241 : 5 : return false;
2242 : :
2243 [ + + ]: 92872 : if (mnOrientation != rOther.mnOrientation)
2244 : 1486 : return false;
2245 : :
2246 [ + + ]: 91386 : if (meLanguage != rOther.meLanguage)
2247 : 214 : return false;
2248 : :
2249 [ - + ]: 91172 : if (mbVertical != rOther.mbVertical)
2250 : 0 : return false;
2251 : :
2252 [ - + ]: 91172 : if (mbNonAntialiased != rOther.mbNonAntialiased)
2253 : 0 : return false;
2254 : :
2255 [ - + ]: 91172 : if (mbEmbolden != rOther.mbEmbolden)
2256 : 0 : return false;
2257 : :
2258 [ - + ]: 91172 : if (maItalicMatrix != rOther.maItalicMatrix)
2259 : 0 : return false;
2260 : :
2261 : 188552 : return true;
2262 : : }
2263 : :
2264 : : // -----------------------------------------------------------------------
2265 : :
2266 : 1369369 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
2267 : : {
2268 : : // check normalized font family name
2269 [ + + ]: 1369369 : if( rA.maSearchName != rB.maSearchName )
2270 : 325522 : return false;
2271 : :
2272 : : // check font transformation
2273 [ + + ][ + + ]: 1043847 : if( (rA.mnHeight != rB.mnHeight)
[ + + ]
2274 : : || (rA.mnWidth != rB.mnWidth)
2275 : : || (rA.mnOrientation != rB.mnOrientation) )
2276 : 122038 : return false;
2277 : :
2278 : : // check mapping relevant attributes
2279 [ + - ][ + + ]: 921809 : if( (rA.mbVertical != rB.mbVertical)
2280 : : || (rA.meLanguage != rB.meLanguage) )
2281 : 2369 : return false;
2282 : :
2283 : : // check font face attributes
2284 [ + + ][ + + ]: 919440 : if( (rA.meWeight != rB.meWeight)
[ + + ]
2285 : : || (rA.meItalic != rB.meItalic)
2286 : : // || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member
2287 : : || (rA.mePitch != rB.mePitch) )
2288 : 49067 : return false;
2289 : :
2290 : : // check style name
2291 [ + + ]: 870373 : if( rA.maStyleName != rB.maStyleName)
2292 : 7023 : return false;
2293 : :
2294 : : // Symbol fonts may recode from one type to another So they are only
2295 : : // safely equivalent for equal targets
2296 [ + + + + ]: 1726832 : if (
[ + - + + ]
[ + + ]
2297 : 8745 : (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
2298 : 854737 : (rB.mpFontData && rB.mpFontData->IsSymbolFont())
2299 : : )
2300 : : {
2301 [ + + ]: 47211 : if (rA.maTargetName != rB.maTargetName)
2302 : 21228 : return false;
2303 : : }
2304 : :
2305 : : #ifdef ENABLE_GRAPHITE
2306 : : // check for features
2307 [ + - - + : 1684244 : if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
# # ][ - + ]
2308 : : != STRING_NOTFOUND ||
2309 : 842122 : rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2310 : 0 : != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
2311 : 0 : return false;
2312 : : #endif
2313 : :
2314 [ - + ]: 842122 : if (rA.mbEmbolden != rB.mbEmbolden)
2315 : 0 : return false;
2316 : :
2317 [ - + ]: 842122 : if (rA.maItalicMatrix != rB.maItalicMatrix)
2318 : 0 : return false;
2319 : :
2320 : 1369369 : return true;
2321 : : }
2322 : :
2323 : : // -----------------------------------------------------------------------
2324 : :
2325 : 2379 : ImplFontCache::ImplFontCache( bool bPrinter )
2326 : : : mpFirstEntry( NULL ),
2327 : : mnRef0Count( 0 ),
2328 [ + - ][ + - ]: 2379 : mbPrinter( bPrinter )
2329 : 2379 : {}
2330 : :
2331 : : // -----------------------------------------------------------------------
2332 : :
2333 [ + - ]: 2138 : ImplFontCache::~ImplFontCache()
2334 : : {
2335 [ + - ]: 2138 : FontInstanceList::iterator it = maFontInstanceList.begin();
2336 [ + - ][ + + ]: 7719 : for(; it != maFontInstanceList.end(); ++it )
2337 : : {
2338 [ + - ]: 5581 : ImplFontEntry* pEntry = (*it).second;
2339 [ + - ][ + - ]: 5581 : delete pEntry;
2340 : : }
2341 : 2138 : }
2342 : :
2343 : : // -----------------------------------------------------------------------
2344 : :
2345 : 841765 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
2346 : : const Font& rFont, const Size& rSize, float fExactHeight, ImplDirectFontSubstitution* pDevSpecific )
2347 : : {
2348 [ + - ][ + - ]: 841765 : String aSearchName = rFont.GetName();
2349 : :
2350 : : // TODO: also add device specific name caching
2351 [ + + ]: 841765 : if( !pDevSpecific )
2352 : : {
2353 : : // check if the requested font name is already known
2354 : : // if it is already known get its normalized search name
2355 [ + - ]: 792741 : FontNameList::const_iterator it_name = maFontNameList.find( aSearchName );
2356 [ + + ][ + - ]: 792741 : if( it_name != maFontNameList.end() )
2357 [ + - ][ + - ]: 1571588 : if( !(*it_name).second.EqualsAscii( "hg", 0, 2)
[ + - ][ + - ]
[ + - ]
2358 : : #ifdef ENABLE_GRAPHITE
2359 [ + - ]: 785794 : && (aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2360 : : == STRING_NOTFOUND)
2361 : : #endif
2362 : : )
2363 [ + - ][ + - ]: 792741 : aSearchName = (*it_name).second;
2364 : : }
2365 : :
2366 : : // initialize internal font request object
2367 [ + - ]: 841765 : FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
2368 [ + - ][ + - ]: 841765 : return GetFontEntry( pFontList, aFontSelData, pDevSpecific );
[ + - ]
2369 : : }
2370 : :
2371 : : // -----------------------------------------------------------------------
2372 : :
2373 : 851122 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
2374 : : FontSelectPattern& aFontSelData, ImplDirectFontSubstitution* pDevSpecific )
2375 : : {
2376 : : // check if a directly matching logical font instance is already cached,
2377 : : // the most recently used font usually has a hit rate of >50%
2378 : 851122 : ImplFontEntry *pEntry = NULL;
2379 : 851122 : ImplDevFontListData* pFontFamily = NULL;
2380 : : IFSD_Equal aIFSD_Equal;
2381 [ + + ][ + - ]: 851122 : if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
[ + + ][ + + ]
2382 : 404654 : pEntry = mpFirstEntry;
2383 : : else
2384 : : {
2385 [ + - ]: 446468 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2386 [ + - ][ + + ]: 446468 : if( it != maFontInstanceList.end() )
2387 [ + - ]: 446468 : pEntry = (*it).second;
2388 : : }
2389 : :
2390 [ + + ]: 851122 : if( !pEntry ) // no direct cache hit
2391 : : {
2392 : : // find the best matching logical font family and update font selector accordingly
2393 [ + - ]: 166011 : pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific );
2394 : : DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
2395 [ + - ]: 166011 : if( pFontFamily )
2396 [ + - ]: 166011 : aFontSelData.maSearchName = pFontFamily->GetSearchName();
2397 : :
2398 : : // check if an indirectly matching logical font instance is already cached
2399 [ + - ]: 166011 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2400 [ + - ][ + + ]: 166011 : if( it != maFontInstanceList.end() )
2401 : : {
2402 : : // we have an indirect cache hit
2403 [ + - ]: 157011 : pEntry = (*it).second;
2404 : : // cache the requested and the selected font names
2405 : : // => next time there is a good chance for a direct cache hit
2406 : : // don't allow the cache to grow too big
2407 : : // TODO: implement some fancy LRU caching?
2408 [ - + ]: 157011 : if( maFontNameList.size() >= 4000 )
2409 [ # # ]: 0 : maFontNameList.clear();
2410 : : // TODO: also add device specific name caching
2411 [ + + ]: 157011 : if( !pDevSpecific )
2412 [ + - ][ + - ]: 108300 : if( aFontSelData.maName != aFontSelData.maSearchName )
2413 [ + - ][ + - ]: 166011 : maFontNameList[ aFontSelData.maName ] = aFontSelData.maSearchName;
2414 : : }
2415 : : }
2416 : :
2417 : 851122 : PhysicalFontFace* pFontData = NULL;
2418 : :
2419 [ + + ][ + - ]: 851122 : if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
2420 : : {
2421 [ + + ][ + + ]: 9000 : bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
2422 [ + - ]: 9000 : pFontData = pFontFamily->FindBestFontFace( aFontSelData );
2423 : 9000 : aFontSelData.mpFontData = pFontData;
2424 [ + - ][ + + ]: 9000 : bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
2425 : :
2426 [ + + ]: 9000 : if (bNewIsSymbol != bOrigWasSymbol)
2427 : : {
2428 : : // it is possible, though generally unlikely, that at this point we
2429 : : // will attempt to use a symbol font as a last-ditch fallback for a
2430 : : // non-symbol font request or vice versa, and by changing
2431 : : // aFontSelData.mpFontData to/from a symbol font we may now find
2432 : : // something in the cache that can be reused which previously
2433 : : // wasn't a candidate
2434 [ + - ]: 1947 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2435 [ + - ][ - + ]: 1947 : if( it != maFontInstanceList.end() )
2436 [ # # ]: 1947 : pEntry = (*it).second;
2437 : : }
2438 : : }
2439 : :
2440 [ + + ]: 851122 : if( pEntry ) // cache hit => use existing font instance
2441 : : {
2442 : : // increase the font instance's reference count
2443 [ + + ]: 842122 : if( !pEntry->mnRefCount++ )
2444 : 175945 : --mnRef0Count;
2445 : : }
2446 : :
2447 [ + + ][ + - ]: 851122 : if (!pEntry && pFontData)// still no cache hit => create a new font instance
2448 : : {
2449 : : // create a new logical font instance from this physical font face
2450 [ + - ]: 9000 : pEntry = pFontData->CreateFontInstance( aFontSelData );
2451 : :
2452 : : // if we found a different symbol font we need a symbol conversion table
2453 [ + + ]: 9000 : if( pFontData->IsSymbolFont() )
2454 [ + - ][ + - ]: 1365 : if( aFontSelData.maTargetName != aFontSelData.maSearchName )
2455 [ + - ]: 1365 : pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
2456 : :
2457 : : // add the new entry to the cache
2458 [ + - ]: 9000 : maFontInstanceList[ aFontSelData ] = pEntry;
2459 : : }
2460 : :
2461 : 851122 : mpFirstEntry = pEntry;
2462 : 851122 : return pEntry;
2463 : : }
2464 : :
2465 : : namespace
2466 : : {
2467 : 114983 : rtl::OUString stripCharSetFromName(rtl::OUString aName)
2468 : : {
2469 : : //I worry that someone will have a font which *does* have
2470 : : //e.g. "Greek" legitimately at the end of its name :-(
2471 : : const char*suffixes[] =
2472 : : {
2473 : : " baltic",
2474 : : " ce",
2475 : : " cyr",
2476 : : " greek",
2477 : : " tur",
2478 : : " (arabic)",
2479 : : " (hebrew)",
2480 : : " (thai)",
2481 : : " (vietnamese)"
2482 : 114983 : };
2483 : :
2484 : : //These can be crazily piled up, e.g. Times New Roman CYR Greek
2485 : 114983 : bool bFinished = false;
2486 [ + + ]: 229966 : while (!bFinished)
2487 : : {
2488 : 114983 : bFinished = true;
2489 [ + + ]: 1149830 : for (size_t i = 0; i < SAL_N_ELEMENTS(suffixes); ++i)
2490 : : {
2491 : 1034847 : size_t nLen = strlen(suffixes[i]);
2492 [ - + ]: 1034847 : if (aName.endsWithIgnoreAsciiCaseAsciiL(suffixes[i], nLen))
2493 : : {
2494 : 0 : bFinished = false;
2495 : 0 : aName = aName.copy(0, aName.getLength() - nLen);
2496 : : }
2497 : : }
2498 : : }
2499 : 114983 : return aName;
2500 : : }
2501 : : }
2502 : :
2503 : : // -----------------------------------------------------------------------
2504 : :
2505 : 166011 : ImplDevFontListData* ImplDevFontList::ImplFindByFont( FontSelectPattern& rFSD,
2506 : : bool bPrinter, ImplDirectFontSubstitution* pDevSpecific ) const
2507 : : {
2508 : : // give up if no fonts are available
2509 [ + - ][ - + ]: 166011 : if( !Count() )
2510 : 0 : return NULL;
2511 : :
2512 : : // test if a font in the token list is available
2513 : : // substitute the font if this was requested
2514 : 166011 : sal_uInt16 nSubstFlags = FONT_SUBSTITUTE_ALWAYS;
2515 [ + + ]: 166011 : if ( bPrinter )
2516 : 229 : nSubstFlags |= FONT_SUBSTITUTE_SCREENONLY;
2517 : :
2518 : 166011 : bool bMultiToken = false;
2519 : 166011 : xub_StrLen nTokenPos = 0;
2520 : 166011 : String& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
2521 : 147379 : for(;;)
2522 : : {
2523 [ + - ][ + - ]: 166011 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
[ + - ]
2524 [ + - ]: 166011 : aSearchName = rFSD.maTargetName;
2525 : :
2526 : : #ifdef ENABLE_GRAPHITE
2527 : : // Until features are properly supported, they are appended to the
2528 : : // font name, so we need to strip them off so the font is found.
2529 [ + - ]: 166011 : xub_StrLen nFeat = aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX);
2530 [ + - ]: 166011 : String aOrigName = rFSD.maTargetName;
2531 [ + - ][ + - ]: 166011 : String aBaseFontName(aSearchName, 0, (nFeat != STRING_NOTFOUND)?nFeat:aSearchName.Len());
2532 [ - + ][ # # ]: 166011 : if (nFeat != STRING_NOTFOUND && STRING_NOTFOUND !=
[ - + ]
2533 [ # # ]: 0 : aSearchName.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
2534 : : {
2535 [ # # ]: 0 : aSearchName = aBaseFontName;
2536 [ # # ]: 0 : rFSD.maTargetName = aBaseFontName;
2537 : : }
2538 : :
2539 : : #endif
2540 : :
2541 [ + - ]: 166011 : GetEnglishSearchFontName( aSearchName );
2542 [ + - ]: 166011 : ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
2543 : : // #114999# special emboldening for Ricoh fonts
2544 : : // TODO: smarter check for special cases by using PreMatch infrastructure?
2545 [ + + ][ - + ]: 203762 : if( (rFSD.meWeight > WEIGHT_MEDIUM)
[ - + ]
2546 [ + - ]: 37751 : && aSearchName.EqualsAscii( "hg", 0, 2) )
2547 : : {
2548 [ # # ]: 0 : String aBoldName;
2549 [ # # ][ # # ]: 0 : if( aSearchName.EqualsAscii( "hggothicb", 0, 9) )
2550 [ # # ][ # # ]: 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hggothice"));
[ # # ]
2551 [ # # ][ # # ]: 0 : else if( aSearchName.EqualsAscii( "hgpgothicb", 0, 10) )
2552 [ # # ][ # # ]: 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpgothice"));
[ # # ]
2553 [ # # ][ # # ]: 0 : else if( aSearchName.EqualsAscii( "hgminchol", 0, 9) )
2554 [ # # ][ # # ]: 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchob"));
[ # # ]
2555 [ # # ][ # # ]: 0 : else if( aSearchName.EqualsAscii( "hgpminchol", 0, 10) )
2556 [ # # ][ # # ]: 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchob"));
[ # # ]
2557 [ # # ][ # # ]: 0 : else if( aSearchName.EqualsAscii( "hgminchob" ) )
2558 [ # # ][ # # ]: 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchoe"));
[ # # ]
2559 [ # # ][ # # ]: 0 : else if( aSearchName.EqualsAscii( "hgpminchob" ) )
2560 [ # # ][ # # ]: 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchoe"));
[ # # ]
2561 : :
2562 [ # # ][ # # ]: 0 : if( aBoldName.Len() && ImplFindBySearchName( aBoldName ) )
[ # # ][ # # ]
2563 : : {
2564 : : // the other font is available => use it
2565 [ # # ]: 0 : aSearchName = aBoldName;
2566 : : // prevent synthetic emboldening of bold version
2567 : 0 : rFSD.meWeight = WEIGHT_DONTKNOW;
2568 [ # # ]: 0 : }
2569 : : }
2570 : :
2571 : : #ifdef ENABLE_GRAPHITE
2572 : : // restore the features to make the font selection data unique
2573 [ + - ]: 166011 : rFSD.maTargetName = aOrigName;
2574 : : #endif
2575 : : // check if the current font name token or its substitute is valid
2576 [ + - ]: 166011 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
2577 [ + + ]: 166011 : if( pFoundData )
2578 : 51028 : return pFoundData;
2579 : :
2580 : : // some systems provide special customization
2581 : : // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
2582 : : // because the system wants to map it to another font first, e.g. "Helvetica"
2583 : : #ifdef ENABLE_GRAPHITE
2584 : : // use the target name to search in the prematch hook
2585 [ + - ]: 114983 : rFSD.maTargetName = aBaseFontName;
2586 : : #endif
2587 : :
2588 : : //Related: fdo#49271 RTF files often contain weird-ass
2589 : : //Win 3.1/Win95 style fontnames which attempt to put the
2590 : : //charset encoding into the filename
2591 : : //http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
2592 [ + - ][ + - ]: 114983 : rtl::OUString sStrippedName = stripCharSetFromName(rFSD.maTargetName);
2593 [ - + ][ + - ]: 114983 : if (!sStrippedName.equals(rFSD.maTargetName))
2594 : : {
2595 [ # # ]: 0 : rFSD.maTargetName = sStrippedName;
2596 [ # # ]: 0 : aSearchName = rFSD.maTargetName;
2597 [ # # ]: 0 : GetEnglishSearchFontName(aSearchName);
2598 [ # # ]: 0 : pFoundData = ImplFindBySearchName(aSearchName);
2599 [ # # ]: 0 : if( pFoundData )
2600 : 0 : return pFoundData;
2601 : : }
2602 : :
2603 [ + - ]: 114983 : if( mpPreMatchHook )
2604 : : {
2605 [ + - ][ + + ]: 114983 : if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
2606 [ + - ]: 96351 : GetEnglishSearchFontName( aSearchName );
2607 : : }
2608 : : #ifdef ENABLE_GRAPHITE
2609 : : // the prematch hook uses the target name to search, but we now need
2610 : : // to restore the features to make the font selection data unique
2611 [ + - ]: 114983 : rFSD.maTargetName = aOrigName;
2612 : : #endif
2613 [ + - ]: 114983 : pFoundData = ImplFindBySearchName( aSearchName );
2614 [ + + ]: 114983 : if( pFoundData )
2615 : 96351 : return pFoundData;
2616 : :
2617 : : // break after last font name token was checked unsuccessfully
2618 [ + - ]: 18632 : if( nTokenPos == STRING_NOTFOUND)
2619 : : break;
2620 [ + + - ]: 114983 : bMultiToken = true;
2621 [ + - ]: 280994 : }
[ + + - ]
[ + - ]
[ - + + ]
2622 : :
2623 : : // if the first font was not available find the next available font in
2624 : : // the semicolon separated list of font names. A font is also considered
2625 : : // available when there is a matching entry in the Tools->Options->Fonts
2626 : : // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
2627 : : // font is available
2628 [ + + ]: 37264 : for( nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
2629 : : {
2630 [ - + ]: 18632 : if( bMultiToken )
2631 : : {
2632 [ # # ][ # # ]: 0 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
[ # # ]
2633 [ # # ]: 0 : aSearchName = rFSD.maTargetName;
2634 [ # # ]: 0 : GetEnglishSearchFontName( aSearchName );
2635 : : }
2636 : : else
2637 : 18632 : nTokenPos = STRING_NOTFOUND;
2638 [ + - ]: 18632 : if( mpPreMatchHook )
2639 [ + - ][ - + ]: 18632 : if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
2640 [ # # ]: 0 : GetEnglishSearchFontName( aSearchName );
2641 [ + - ]: 18632 : ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
2642 [ + - ]: 18632 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
2643 [ - + ]: 18632 : if( pFoundData )
2644 : 0 : return pFoundData;
2645 : : }
2646 : :
2647 : : // if no font with a directly matching name is available use the
2648 : : // first font name token and get its attributes to find a replacement
2649 [ - + ]: 18632 : if ( bMultiToken )
2650 : : {
2651 : 0 : nTokenPos = 0;
2652 [ # # ][ # # ]: 0 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
[ # # ]
2653 [ # # ]: 0 : aSearchName = rFSD.maTargetName;
2654 [ # # ]: 0 : GetEnglishSearchFontName( aSearchName );
2655 : : }
2656 : :
2657 [ + - ]: 18632 : String aSearchShortName;
2658 [ + - ]: 18632 : String aSearchFamilyName;
2659 : 18632 : FontWeight eSearchWeight = rFSD.meWeight;
2660 : 18632 : FontWidth eSearchWidth = rFSD.meWidthType;
2661 : 18632 : sal_uLong nSearchType = 0;
2662 : : FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
2663 [ + - ]: 18632 : eSearchWeight, eSearchWidth, nSearchType );
2664 : :
2665 : : // note: the search name was already translated to english (if possible)
2666 : :
2667 : : // use the font's shortened name if needed
2668 [ + - ][ - + ]: 18632 : if ( aSearchShortName != aSearchName )
2669 : : {
2670 [ # # ]: 0 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchShortName );
2671 [ # # ]: 0 : if( pFoundData )
2672 : : {
2673 : : #ifdef UNX
2674 : : /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
2675 : : a korean bitmap font that is not suitable here. Use the font replacement table,
2676 : : that automatically leads to the desired "HG Mincho Light J". Same story for
2677 : : MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
2678 [ # # ][ # # ]: 0 : static String aMS_Mincho( RTL_CONSTASCII_USTRINGPARAM("msmincho") );
[ # # ][ # # ]
2679 [ # # ][ # # ]: 0 : static String aMS_Gothic( RTL_CONSTASCII_USTRINGPARAM("msgothic") );
[ # # ][ # # ]
2680 [ # # ][ # # ]: 0 : if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
[ # # ][ # # ]
[ # # ]
2681 : : // TODO: add heuristic to only throw out the fake ms* fonts
2682 : : #endif
2683 : : {
2684 : 0 : return pFoundData;
2685 : : }
2686 : : }
2687 : : }
2688 : :
2689 : : // use font fallback
2690 : 18632 : const FontNameAttr* pFontAttr = NULL;
2691 [ + - ]: 18632 : if( aSearchName.Len() )
2692 : : {
2693 : : // get fallback info using FontSubstConfiguration and
2694 : : // the target name, it's shortened name and family name in that order
2695 [ + - ]: 18632 : const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
2696 [ + - ][ + - ]: 18632 : pFontAttr = rFontSubst.getSubstInfo( aSearchName );
2697 [ # # ][ # # ]: 18632 : if ( !pFontAttr && (aSearchShortName != aSearchName) )
[ - + ][ - + ]
2698 [ # # ][ # # ]: 0 : pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
2699 [ - + ][ # # ]: 18632 : if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
[ # # ][ - + ]
2700 [ # # ][ # # ]: 0 : pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
2701 : :
2702 : : // try the font substitutions suggested by the fallback info
2703 [ + - ]: 18632 : if( pFontAttr )
2704 : : {
2705 [ + - ]: 18632 : ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
2706 [ + - ]: 18632 : if( pFoundData )
2707 : 18632 : return pFoundData;
2708 : : }
2709 : : }
2710 : :
2711 : : // if a target symbol font is not available use a default symbol font
2712 [ # # ]: 0 : if( rFSD.IsSymbolFont() )
2713 : : {
2714 [ # # ]: 0 : com::sun::star::lang::Locale aDefaultLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2715 [ # # ][ # # ]: 0 : aSearchName = DefaultFontConfiguration::get().getDefaultFont( aDefaultLocale, DEFAULTFONT_SYMBOL );
[ # # ]
2716 [ # # ][ # # ]: 0 : ImplDevFontListData* pFoundData = ImplFindByTokenNames( aSearchName );
2717 [ # # ]: 0 : if( pFoundData )
2718 [ # # ]: 0 : return pFoundData;
2719 : : }
2720 : :
2721 : : // now try the other font name tokens
2722 [ # # ]: 0 : while( nTokenPos != STRING_NOTFOUND )
2723 : : {
2724 [ # # ][ # # ]: 0 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
[ # # ]
2725 [ # # ]: 0 : if( !rFSD.maTargetName.Len() )
2726 : 0 : continue;
2727 : :
2728 [ # # ]: 0 : aSearchName = rFSD.maTargetName;
2729 [ # # ]: 0 : GetEnglishSearchFontName( aSearchName );
2730 : :
2731 [ # # ]: 0 : String aTempShortName;
2732 [ # # ]: 0 : String aTempFamilyName;
2733 : 0 : sal_uLong nTempType = 0;
2734 : 0 : FontWeight eTempWeight = rFSD.meWeight;
2735 : 0 : FontWidth eTempWidth = WIDTH_DONTKNOW;
2736 : : FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
2737 [ # # ]: 0 : eTempWeight, eTempWidth, nTempType );
2738 : :
2739 : : // use a shortend token name if available
2740 [ # # ][ # # ]: 0 : if( aTempShortName != aSearchName )
2741 : : {
2742 [ # # ]: 0 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aTempShortName );
2743 [ # # ]: 0 : if( pFoundData )
2744 : 0 : return pFoundData;
2745 : : }
2746 : :
2747 : : // use a font name from font fallback list to determine font attributes
2748 : :
2749 : : // get fallback info using FontSubstConfiguration and
2750 : : // the target name, it's shortened name and family name in that order
2751 [ # # ]: 0 : const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
2752 [ # # ][ # # ]: 0 : const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
2753 [ # # ][ # # ]: 0 : if ( !pTempFontAttr && (aTempShortName != aSearchName) )
[ # # ][ # # ]
2754 [ # # ][ # # ]: 0 : pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
2755 [ # # ][ # # ]: 0 : if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
[ # # ][ # # ]
2756 [ # # ][ # # ]: 0 : pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
2757 : :
2758 : : // try the font substitutions suggested by the fallback info
2759 [ # # ]: 0 : if( pTempFontAttr )
2760 : : {
2761 [ # # ]: 0 : ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
2762 [ # # ]: 0 : if( pFoundData )
2763 : 0 : return pFoundData;
2764 [ # # ]: 0 : if( !pFontAttr )
2765 : 0 : pFontAttr = pTempFontAttr;
2766 : : }
2767 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
2768 : :
2769 : : // if still needed use the alias names of the installed fonts
2770 [ # # ]: 0 : if( mbMapNames )
2771 : : {
2772 [ # # ][ # # ]: 0 : ImplDevFontListData* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
[ # # ]
2773 [ # # ]: 0 : if( pFoundData )
2774 : 0 : return pFoundData;
2775 : : }
2776 : :
2777 : : // if still needed use the font request's attributes to find a good match
2778 [ # # ][ # # ]: 0 : if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
2779 : 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
2780 [ # # ][ # # ]: 0 : else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
2781 : 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
2782 [ # # ][ # # ]: 0 : else if (MsLangId::isKorean(rFSD.meLanguage))
2783 : 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
2784 [ # # ]: 0 : else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
2785 : 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
2786 : : else
2787 : : {
2788 : 0 : nSearchType |= ImplIsCJKFont( rFSD.maName );
2789 [ # # ]: 0 : if( rFSD.IsSymbolFont() )
2790 : 0 : nSearchType |= IMPL_FONT_ATTR_SYMBOL;
2791 : : }
2792 : :
2793 : 0 : ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.meFamily, pFontAttr );
2794 : : ImplDevFontListData* pFoundData = ImplFindByAttributes( nSearchType,
2795 [ # # ][ # # ]: 0 : eSearchWeight, eSearchWidth, rFSD.meItalic, aSearchFamilyName );
2796 : :
2797 [ # # ]: 0 : if( pFoundData )
2798 : : {
2799 : : // overwrite font selection attributes using info from the typeface flags
2800 [ # # ][ # # ]: 0 : if( (eSearchWeight >= WEIGHT_BOLD)
[ # # ]
2801 : : && (eSearchWeight > rFSD.meWeight)
2802 : : && (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) )
2803 : 0 : rFSD.meWeight = eSearchWeight;
2804 [ # # ][ # # ]: 0 : else if( (eSearchWeight < WEIGHT_NORMAL)
[ # # ][ # # ]
2805 : : && (eSearchWeight < rFSD.meWeight)
2806 : : && (eSearchWeight != WEIGHT_DONTKNOW)
2807 : : && (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) )
2808 : 0 : rFSD.meWeight = eSearchWeight;
2809 : :
2810 [ # # ][ # # ]: 0 : if( (nSearchType & IMPL_FONT_ATTR_ITALIC)
[ # # ][ # # ]
2811 : : && ((rFSD.meItalic == ITALIC_DONTKNOW) || (rFSD.meItalic == ITALIC_NONE))
2812 : : && (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) )
2813 : 0 : rFSD.meItalic = ITALIC_NORMAL;
2814 : : }
2815 : : else
2816 : : {
2817 : : // if still needed fall back to default fonts
2818 [ # # ]: 0 : pFoundData = FindDefaultFont();
2819 : : }
2820 : :
2821 [ + - ][ + - ]: 166011 : return pFoundData;
2822 : : }
2823 : :
2824 : : // -----------------------------------------------------------------------
2825 : :
2826 : 9357 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList* pFontList,
2827 : : FontSelectPattern& rFontSelData, int nFallbackLevel, rtl::OUString& rMissingCodes )
2828 : : {
2829 : : // get a candidate font for glyph fallback
2830 : : // unless the previously selected font got a device specific substitution
2831 : : // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
2832 [ + - ]: 9357 : if( nFallbackLevel >= 1)
2833 : : {
2834 : 9357 : ImplDevFontListData* pFallbackData = NULL;
2835 : :
2836 : : //fdo#33898 If someone has EUDC installed then they really want that to
2837 : : //be used as the first-choice glyph fallback seeing as it's filled with
2838 : : //private area codes with don't make any sense in any other font so
2839 : : //prioritise it here if it's available. Ideally we would remove from
2840 : : //rMissingCodes all the glyphs which it is able to resolve as an
2841 : : //optimization, but that's tricky to achieve cross-platform without
2842 : : //sufficient heavy-weight code that's likely to undo the value of the
2843 : : //optimization
2844 [ + - ]: 9357 : if (nFallbackLevel == 1)
2845 [ + - ][ + - ]: 9357 : pFallbackData = pFontList->FindFontFamily(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EUDC")));
[ + - ]
2846 [ + - ]: 9357 : if (!pFallbackData)
2847 : 9357 : pFallbackData = pFontList->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
2848 : : // escape when there are no font candidates
2849 [ - + ]: 9357 : if( !pFallbackData )
2850 : 0 : return NULL;
2851 : : // override the font name
2852 : 9357 : rFontSelData.maName = pFallbackData->GetFamilyName();
2853 : : // clear the cached normalized name
2854 [ + - ]: 9357 : rFontSelData.maSearchName = String();
2855 : : }
2856 : :
2857 : : // get device font without doing device specific substitutions
2858 : 9357 : ImplFontEntry* pFallbackFont = GetFontEntry( pFontList, rFontSelData, NULL );
2859 : 9357 : return pFallbackFont;
2860 : : }
2861 : :
2862 : : // -----------------------------------------------------------------------
2863 : :
2864 : 753509 : void ImplFontCache::Release( ImplFontEntry* pEntry )
2865 : : {
2866 : : static const int FONTCACHE_MAX = 50;
2867 : :
2868 : : DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
2869 [ + + ]: 753509 : if( --pEntry->mnRefCount > 0 )
2870 : : return;
2871 : :
2872 [ + + ]: 183740 : if( ++mnRef0Count < FONTCACHE_MAX )
2873 : : return;
2874 : :
2875 : : // remove unused entries from font instance cache
2876 [ + - ]: 27 : FontInstanceList::iterator it_next = maFontInstanceList.begin();
2877 [ + - ][ + + ]: 755091 : while( it_next != maFontInstanceList.end() )
2878 : : {
2879 [ + - ]: 1582 : FontInstanceList::iterator it = it_next++;
2880 [ + - ]: 1582 : ImplFontEntry* pFontEntry = (*it).second;
2881 [ + + ]: 1582 : if( pFontEntry->mnRefCount > 0 )
2882 : 232 : continue;
2883 : :
2884 [ + - ]: 1350 : maFontInstanceList.erase( it );
2885 [ + - ][ + - ]: 1350 : delete pFontEntry;
2886 : 1350 : --mnRef0Count;
2887 : : DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
2888 : :
2889 [ + + ]: 1350 : if( mpFirstEntry == pFontEntry )
2890 : 1350 : mpFirstEntry = NULL;
2891 : : }
2892 : :
2893 : : DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
2894 : : }
2895 : :
2896 : : // -----------------------------------------------------------------------
2897 : :
2898 : 5 : void ImplFontCache::Invalidate()
2899 : : {
2900 : : // delete unreferenced entries
2901 [ + - ]: 5 : FontInstanceList::iterator it = maFontInstanceList.begin();
2902 [ + - ][ - + ]: 5 : for(; it != maFontInstanceList.end(); ++it )
2903 : : {
2904 [ # # ]: 0 : ImplFontEntry* pFontEntry = (*it).second;
2905 [ # # ]: 0 : if( pFontEntry->mnRefCount > 0 )
2906 : 0 : continue;
2907 : :
2908 [ # # ][ # # ]: 0 : delete pFontEntry;
2909 : 0 : --mnRef0Count;
2910 : : }
2911 : :
2912 : : // #112304# make sure the font cache is really clean
2913 : 5 : mpFirstEntry = NULL;
2914 [ + - ]: 5 : maFontInstanceList.clear();
2915 : :
2916 : : DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
2917 : 5 : }
2918 : :
2919 : : // =======================================================================
2920 : :
2921 : 2634 : ImplMultiTextLineInfo::ImplMultiTextLineInfo()
2922 : : {
2923 : 2634 : mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
2924 : 2634 : mnLines = 0;
2925 : 2634 : mnSize = MULTITEXTLINEINFO_RESIZE;
2926 : 2634 : }
2927 : :
2928 : :
2929 : 2634 : ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
2930 : : {
2931 [ + + ]: 5038 : for ( xub_StrLen i = 0; i < mnLines; i++ )
2932 : 2404 : delete mpLines[i];
2933 [ + - ]: 2634 : delete [] mpLines;
2934 : 2634 : }
2935 : :
2936 : 2404 : void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
2937 : : {
2938 [ - + ]: 2404 : if ( mnSize == mnLines )
2939 : : {
2940 : 0 : mnSize += MULTITEXTLINEINFO_RESIZE;
2941 : 0 : PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
2942 : 0 : memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
2943 : 0 : mpLines = pNewLines;
2944 : : }
2945 : :
2946 : 2404 : mpLines[mnLines] = pLine;
2947 : 2404 : mnLines++;
2948 : 2404 : }
2949 : :
2950 : 2634 : void ImplMultiTextLineInfo::Clear()
2951 : : {
2952 [ - + ]: 2634 : for ( xub_StrLen i = 0; i < mnLines; i++ )
2953 : 0 : delete mpLines[i];
2954 : 2634 : mnLines = 0;
2955 : 2634 : }
2956 : :
2957 : : // =======================================================================
2958 : :
2959 : 69806 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
2960 : : {
2961 : 69806 : FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
2962 : :
2963 : : // If no Position is set, then calculate the default position, which
2964 : : // depends on the language
2965 [ + + ]: 69806 : if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
2966 : : {
2967 : 11727 : LanguageType eLang = rFont.GetLanguage();
2968 : : // In Chinese Simplified the EmphasisMarks are below/left
2969 [ - + ]: 11727 : if (MsLangId::isSimplifiedChinese(eLang))
2970 : 0 : nEmphasisMark |= EMPHASISMARK_POS_BELOW;
2971 : : else
2972 : : {
2973 : 11727 : eLang = rFont.GetCJKContextLanguage();
2974 : : // In Chinese Simplified the EmphasisMarks are below/left
2975 [ - + ]: 11727 : if (MsLangId::isSimplifiedChinese(eLang))
2976 : 0 : nEmphasisMark |= EMPHASISMARK_POS_BELOW;
2977 : : else
2978 : 11727 : nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
2979 : : }
2980 : : }
2981 : :
2982 : 69806 : return nEmphasisMark;
2983 : : }
2984 : :
2985 : : // -----------------------------------------------------------------------
2986 : :
2987 : 15446 : sal_Bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
2988 : : {
2989 [ + - ]: 15446 : if ( !rFont.IsVertical() )
2990 : 15446 : return sal_False;
2991 : :
2992 [ # # # # ]: 0 : if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
[ # # ]
2993 : 0 : || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
2994 : : // the underline is right for Japanese only
2995 : 0 : return sal_True;
2996 : :
2997 : 15446 : return sal_False;
2998 : : }
2999 : :
3000 : : // =======================================================================
3001 : :
3002 : 1368848 : void OutputDevice::ImplInitFontList() const
3003 : : {
3004 [ + + ]: 1368848 : if( ! mpFontList->Count() )
3005 : : {
3006 [ - + ][ # # ]: 242 : if( mpGraphics || ImplGetGraphics() )
[ + - ]
3007 : : {
3008 : : RTL_LOGFILE_CONTEXT( aLog, "OutputDevice::ImplInitFontList()" );
3009 : 242 : mpGraphics->GetDevFontList( mpFontList );
3010 : : }
3011 : : }
3012 [ + + ][ - + ]: 1368848 : if( meOutDevType == OUTDEV_WINDOW && ! mpFontList->Count() )
[ - + ]
3013 : : {
3014 [ # # ]: 0 : String aError( RTL_CONSTASCII_USTRINGPARAM( "Application error: no fonts and no vcl resource found on your system" ) );
3015 [ # # ]: 0 : ResMgr* pMgr = ImplGetResMgr();
3016 [ # # ]: 0 : if( pMgr )
3017 : : {
3018 [ # # ][ # # ]: 0 : String aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
3019 [ # # ]: 0 : if( aResStr.Len() )
3020 [ # # ][ # # ]: 0 : aError = aResStr;
3021 : : }
3022 [ # # ][ # # ]: 0 : Application::Abort( aError );
3023 : : }
3024 : 1368848 : }
3025 : :
3026 : : // =======================================================================
3027 : :
3028 : 183958 : void OutputDevice::ImplInitFont() const
3029 : : {
3030 : : DBG_TESTSOLARMUTEX();
3031 : :
3032 [ - + ]: 183958 : if (!mpFontEntry)
3033 : 183958 : return;
3034 : :
3035 [ + - ]: 183958 : if ( mbInitFont )
3036 : : {
3037 [ + + ]: 183958 : if ( meOutDevType != OUTDEV_PRINTER )
3038 : : {
3039 : : // decide if antialiasing is appropriate
3040 : 183645 : bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
3041 : 183645 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3042 : 183645 : bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
3043 : 183645 : bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
3044 : 183645 : mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
3045 : : }
3046 : :
3047 [ - + ][ # # ]: 183958 : if( !mpPDFWriter || !mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
[ + - ]
3048 : : {
3049 : : // select font in the device layers
3050 : 183958 : mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
3051 : : }
3052 : 183958 : mbInitFont = false;
3053 : : }
3054 : : }
3055 : :
3056 : : // -----------------------------------------------------------------------
3057 : :
3058 : 61581 : void OutputDevice::ImplInitTextColor()
3059 : : {
3060 : : DBG_TESTSOLARMUTEX();
3061 : :
3062 [ + + ]: 61581 : if ( mbInitTextColor )
3063 : : {
3064 : 56597 : mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
3065 : 56597 : mbInitTextColor = sal_False;
3066 : : }
3067 : 61581 : }
3068 : :
3069 : : // -----------------------------------------------------------------------
3070 : :
3071 : 1111898 : bool OutputDevice::ImplNewFont() const
3072 : : {
3073 : : DBG_TESTSOLARMUTEX();
3074 : :
3075 : : // get correct font list on the PDF writer if necessary
3076 [ - + ]: 1111898 : if( mpPDFWriter )
3077 : : {
3078 [ # # ]: 0 : const ImplSVData* pSVData = ImplGetSVData();
3079 [ # # ][ # # ]: 0 : if( mpFontList == pSVData->maGDIData.mpScreenFontList
3080 : : || mpFontCache == pSVData->maGDIData.mpScreenFontCache )
3081 [ # # ]: 0 : const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
3082 : : }
3083 : :
3084 [ + + ]: 1111898 : if ( !mbNewFont )
3085 : 367515 : return true;
3086 : :
3087 : : // we need a graphics
3088 [ + + ][ + - ]: 744383 : if ( !mpGraphics && !ImplGetGraphics() )
[ - + ][ - + ]
3089 : 0 : return false;
3090 : 744383 : SalGraphics* pGraphics = mpGraphics;
3091 [ + - ]: 744383 : ImplInitFontList();
3092 : :
3093 : : // convert to pixel height
3094 : : // TODO: replace integer based aSize completely with subpixel accurate type
3095 [ + - ][ + - ]: 744383 : float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
3096 [ + - ][ + - ]: 744383 : Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
3097 [ + + ]: 744383 : if ( !aSize.Height() )
3098 : : {
3099 : : // use default pixel height only when logical height is zero
3100 [ + - ][ - + ]: 99 : if ( maFont.GetSize().Height() )
3101 : 0 : aSize.Height() = 1;
3102 : : else
3103 : 99 : aSize.Height() = (12*mnDPIY)/72;
3104 : 99 : fExactHeight = static_cast<float>(aSize.Height());
3105 : : }
3106 : :
3107 : : // select the default width only when logical width is zero
3108 [ + + ][ + - ]: 744383 : if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
[ + + ][ + + ]
3109 : 114 : aSize.Width() = 1;
3110 : :
3111 : : // get font entry
3112 : 744383 : ImplDirectFontSubstitution* pDevSpecificSubst = NULL;
3113 [ + + ]: 744383 : if( mpOutDevData )
3114 : 49024 : pDevSpecificSubst = &mpOutDevData->maDevFontSubst;
3115 : 744383 : ImplFontEntry* pOldEntry = mpFontEntry;
3116 [ + - ]: 744383 : mpFontEntry = mpFontCache->GetFontEntry( mpFontList, maFont, aSize, fExactHeight, pDevSpecificSubst );
3117 [ + + ]: 744383 : if( pOldEntry )
3118 [ + - ]: 691740 : mpFontCache->Release( pOldEntry );
3119 : :
3120 : 744383 : ImplFontEntry* pFontEntry = mpFontEntry;
3121 : :
3122 [ - + ]: 744383 : if (!pFontEntry)
3123 : 0 : return false;
3124 : :
3125 : : // mark when lower layers need to get involved
3126 : 744383 : mbNewFont = sal_False;
3127 [ + + ]: 744383 : if( pFontEntry != pOldEntry )
3128 : 267313 : mbInitFont = sal_True;
3129 : :
3130 : : // select font when it has not been initialized yet
3131 [ + + ]: 744383 : if ( !pFontEntry->mbInit )
3132 : : {
3133 [ + - ]: 7334 : ImplInitFont();
3134 : :
3135 : : // get metric data from device layers
3136 [ + - ]: 7334 : if ( pGraphics )
3137 : : {
3138 : 7334 : pFontEntry->mbInit = true;
3139 : :
3140 : 7334 : pFontEntry->maMetric.mnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
3141 [ # # ][ # # ]: 7334 : if( mpPDFWriter && mpPDFWriter->isBuiltinFont( pFontEntry->maFontSelData.mpFontData ) )
[ - + ][ - + ]
3142 [ # # ]: 0 : mpPDFWriter->getFontMetric( &pFontEntry->maFontSelData, &(pFontEntry->maMetric) );
3143 : : else
3144 [ + - ]: 7334 : pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
3145 : :
3146 : 7334 : pFontEntry->maMetric.ImplInitTextLineSize( this );
3147 : 7334 : pFontEntry->maMetric.ImplInitAboveTextLineSize();
3148 : :
3149 : 7334 : pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
3150 : :
3151 [ - + ][ # # ]: 7334 : if( pFontEntry->maFontSelData.mnOrientation
[ + + ]
3152 : 442 : && !pFontEntry->maMetric.mnOrientation
3153 : : && (meOutDevType != OUTDEV_PRINTER) )
3154 : : {
3155 : 0 : pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
3156 : 0 : pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
3157 : : }
3158 : : else
3159 : 7334 : pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
3160 : : }
3161 : : }
3162 : :
3163 : : // enable kerning array if requested
3164 [ + - ][ + + ]: 744383 : if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
3165 : : {
3166 : : // TODO: test if physical font supports kerning and disable if not
3167 [ + + ]: 101905 : if( pFontEntry->maMetric.mbKernableFont )
3168 : 95101 : mbKerning = true;
3169 : : }
3170 : : else
3171 : 642478 : mbKerning = false;
3172 [ + - ][ - + ]: 744383 : if ( maFont.GetKerning() & KERNING_ASIAN )
3173 : 0 : mbKerning = true;
3174 : :
3175 : : // calculate EmphasisArea
3176 : 744383 : mnEmphasisAscent = 0;
3177 : 744383 : mnEmphasisDescent = 0;
3178 [ + - ][ + + ]: 744383 : if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
3179 : : {
3180 [ + - ]: 55346 : FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
3181 : 55346 : long nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
3182 [ + + ]: 55346 : if ( nEmphasisHeight < 1 )
3183 : 164 : nEmphasisHeight = 1;
3184 [ - + ]: 55346 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
3185 : 0 : mnEmphasisDescent = nEmphasisHeight;
3186 : : else
3187 : 55346 : mnEmphasisAscent = nEmphasisHeight;
3188 : : }
3189 : :
3190 : : // calculate text offset depending on TextAlignment
3191 [ + - ]: 744383 : TextAlign eAlign = maFont.GetAlign();
3192 [ + + ]: 744383 : if ( eAlign == ALIGN_BASELINE )
3193 : : {
3194 : 654694 : mnTextOffX = 0;
3195 : 654694 : mnTextOffY = 0;
3196 : : }
3197 [ + + ]: 89689 : else if ( eAlign == ALIGN_TOP )
3198 : : {
3199 : 87044 : mnTextOffX = 0;
3200 : 87044 : mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
3201 [ + + ]: 87044 : if ( pFontEntry->mnOrientation )
3202 : 9689 : ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
3203 : : }
3204 : : else // eAlign == ALIGN_BOTTOM
3205 : : {
3206 : 2645 : mnTextOffX = 0;
3207 : 2645 : mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
3208 [ - + ]: 2645 : if ( pFontEntry->mnOrientation )
3209 : 0 : ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
3210 : : }
3211 : :
3212 [ + - ][ + - ]: 801671 : mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
3213 [ + - ][ + - ]: 695367 : ((maFont.GetOverline() != UNDERLINE_NONE) && (maFont.GetOverline() != UNDERLINE_DONTKNOW)) ||
3214 [ + + ][ + + ]: 1497038 : ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
[ + + ][ + + ]
[ + - ][ + + ]
[ + - ][ + - ]
3215 [ + - ][ + - ]: 1463000 : mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() ||
3216 [ + + ][ + + ]: 1463000 : (maFont.GetRelief() != RELIEF_NONE);
[ + - ][ + + ]
3217 : :
3218 : : // #95414# fix for OLE objects which use scale factors very creatively
3219 [ + + ][ + + ]: 744383 : if( mbMap && !aSize.Width() )
[ + + ]
3220 : : {
3221 : 619294 : int nOrigWidth = pFontEntry->maMetric.mnWidth;
3222 : 619294 : float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
3223 : 619294 : fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
3224 : 619294 : int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
3225 [ + + ][ + - ]: 619294 : if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
3226 : : {
3227 [ + - ]: 56 : Size aOrigSize = maFont.GetSize();
3228 [ + - ]: 56 : const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
3229 : 56 : mbMap = sal_False;
3230 : 56 : mbNewFont = sal_True;
3231 [ + - ]: 56 : ImplNewFont(); // recurse once using stretched width
3232 : 56 : mbMap = sal_True;
3233 [ + - ]: 56 : const_cast<Font&>(maFont).SetSize( aOrigSize );
3234 : : }
3235 : : }
3236 : :
3237 : 1111898 : return true;
3238 : : }
3239 : :
3240 : : // -----------------------------------------------------------------------
3241 : :
3242 : 93887 : void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
3243 : : long nDistX, long nDistY, long nWidth, long nHeight )
3244 : : {
3245 : 93887 : long nX = nDistX;
3246 : 93887 : long nY = nDistY;
3247 : :
3248 : 93887 : short nOrientation = mpFontEntry->mnOrientation;
3249 [ + + ]: 93887 : if ( nOrientation )
3250 : : {
3251 : : // Rotate rect without rounding problems for 90 degree rotations
3252 [ + + ]: 46119 : if ( !(nOrientation % 900) )
3253 : : {
3254 [ - + ]: 32234 : if ( nOrientation == 900 )
3255 : : {
3256 : 0 : long nTemp = nX;
3257 : 0 : nX = nY;
3258 : 0 : nY = -nTemp;
3259 : 0 : nTemp = nWidth;
3260 : 0 : nWidth = nHeight;
3261 : 0 : nHeight = nTemp;
3262 : 0 : nY -= nHeight;
3263 : : }
3264 [ - + ]: 32234 : else if ( nOrientation == 1800 )
3265 : : {
3266 : 0 : nX = -nX;
3267 : 0 : nY = -nY;
3268 : 0 : nX -= nWidth;
3269 : 0 : nY -= nHeight;
3270 : : }
3271 : : else /* ( nOrientation == 2700 ) */
3272 : : {
3273 : 32234 : long nTemp = nX;
3274 : 32234 : nX = -nY;
3275 : 32234 : nY = nTemp;
3276 : 32234 : nTemp = nWidth;
3277 : 32234 : nWidth = nHeight;
3278 : 32234 : nHeight = nTemp;
3279 : 32234 : nX -= nWidth;
3280 : : }
3281 : : }
3282 : : else
3283 : : {
3284 : 13885 : nX += nBaseX;
3285 : 13885 : nY += nBaseY;
3286 : : // inflate because polygons are drawn smaller
3287 [ + - ]: 13885 : Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
3288 [ + - ]: 13885 : Polygon aPoly( aRect );
3289 [ + - ]: 13885 : aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
3290 [ + - ]: 13885 : ImplDrawPolygon( aPoly );
3291 [ + - ]: 93887 : return;
3292 : : }
3293 : : }
3294 : :
3295 : 80002 : nX += nBaseX;
3296 : 80002 : nY += nBaseY;
3297 : 80002 : mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
3298 : : }
3299 : :
3300 : : // -----------------------------------------------------------------------
3301 : :
3302 : 5844 : void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
3303 : : {
3304 [ + - ]: 5844 : const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
3305 : 5844 : const Point aBase = rSalLayout.DrawBase();
3306 : 5844 : const long nX = aBase.X();
3307 : 5844 : const long nY = aBase.Y();
3308 : :
3309 [ + + ][ + + ]: 5844 : if ( mbLineColor || mbInitLineColor )
3310 : : {
3311 [ + - ]: 5794 : mpGraphics->SetLineColor();
3312 : 5794 : mbInitLineColor = sal_True;
3313 : : }
3314 [ + - ][ + - ]: 5844 : mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
3315 : 5844 : mbInitFillColor = sal_True;
3316 : :
3317 : : ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
3318 : : nWidth,
3319 [ + - ]: 5844 : mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
3320 : 5844 : }
3321 : :
3322 : : // -----------------------------------------------------------------------
3323 : :
3324 : 0 : Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
3325 : : {
3326 [ # # ]: 0 : Point aPoint = rSalLayout.GetDrawPosition();
3327 : 0 : long nX = aPoint.X();
3328 : 0 : long nY = aPoint.Y();
3329 : :
3330 [ # # ]: 0 : long nWidth = rSalLayout.GetTextWidth();
3331 : 0 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
3332 : :
3333 : 0 : nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
3334 : :
3335 [ # # ]: 0 : if ( mpFontEntry->mnOrientation )
3336 : : {
3337 : 0 : long nBaseX = nX, nBaseY = nY;
3338 [ # # ]: 0 : if ( !(mpFontEntry->mnOrientation % 900) )
3339 : : {
3340 : 0 : long nX2 = nX+nWidth;
3341 : 0 : long nY2 = nY+nHeight;
3342 : 0 : ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
3343 : 0 : ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
3344 : 0 : nWidth = nX2-nX;
3345 : 0 : nHeight = nY2-nY;
3346 : : }
3347 : : else
3348 : : {
3349 : : // inflate by +1+1 because polygons are drawn smaller
3350 [ # # ]: 0 : Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
3351 [ # # ]: 0 : Polygon aPoly( aRect );
3352 [ # # ]: 0 : aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
3353 [ # # ][ # # ]: 0 : return aPoly.GetBoundRect();
3354 : : }
3355 : : }
3356 : :
3357 [ # # ]: 0 : return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
3358 : : }
3359 : :
3360 : : // -----------------------------------------------------------------------
3361 : :
3362 : 0 : void OutputDevice::ImplInitTextLineSize()
3363 : : {
3364 : 0 : mpFontEntry->maMetric.ImplInitTextLineSize( this );
3365 : 0 : }
3366 : :
3367 : : // -----------------------------------------------------------------------
3368 : :
3369 : 0 : void OutputDevice::ImplInitAboveTextLineSize()
3370 : : {
3371 : 0 : mpFontEntry->maMetric.ImplInitAboveTextLineSize();
3372 : 0 : }
3373 : :
3374 : : // -----------------------------------------------------------------------
3375 : :
3376 : 188552 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
3377 : : {
3378 [ + + ]: 188552 : if (maName != rOther.maName)
3379 : 33727 : return false;
3380 : :
3381 [ + + ]: 154825 : if (maStyleName != rOther.maStyleName)
3382 : 3111 : return false;
3383 : :
3384 [ + + ]: 151714 : if (meWeight != rOther.meWeight)
3385 : 2635 : return false;
3386 : :
3387 [ + + ]: 149079 : if (meItalic != rOther.meItalic)
3388 : 5294 : return false;
3389 : :
3390 [ + + ]: 143785 : if (meFamily != rOther.meFamily)
3391 : 3944 : return false;
3392 : :
3393 [ + + ]: 139841 : if (mePitch != rOther.mePitch)
3394 : 557 : return false;
3395 : :
3396 [ - + ]: 139284 : if (meWidthType != rOther.meWidthType)
3397 : 0 : return false;
3398 : :
3399 [ - + ]: 139284 : if (mbSymbolFlag != rOther.mbSymbolFlag)
3400 : 0 : return false;
3401 : :
3402 : 188552 : return true;
3403 : : }
3404 : :
3405 : : // -----------------------------------------------------------------------
3406 : :
3407 : 18357 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
3408 : 18357 : : ImplFontAttributes( rFontSelData )
3409 : : {
3410 : : // initialize the members provided by the font request
3411 : 18357 : mnWidth = rFontSelData.mnWidth;
3412 : 18357 : mnOrientation = sal::static_int_cast<short>(rFontSelData.mnOrientation);
3413 : :
3414 : : // intialize the used font name
3415 [ + - ]: 18357 : if( rFontSelData.mpFontData )
3416 : : {
3417 [ + - ]: 18357 : maName = rFontSelData.mpFontData->maName;
3418 [ + - ]: 18357 : maStyleName= rFontSelData.mpFontData->maStyleName;
3419 : 18357 : mbDevice = rFontSelData.mpFontData->mbDevice;
3420 : 18357 : mbKernableFont = true;
3421 : : }
3422 : : else
3423 : : {
3424 : 0 : xub_StrLen nTokenPos = 0;
3425 [ # # ][ # # ]: 0 : maName = GetNextFontToken( rFontSelData.maName, nTokenPos );
[ # # ]
3426 [ # # ]: 0 : maStyleName= rFontSelData.maStyleName;
3427 : 0 : mbDevice = false;
3428 : 0 : mbKernableFont = false;
3429 : : }
3430 : :
3431 : : // reset metrics that are usually measured for the font instance
3432 : 18357 : mnAscent = 0;
3433 : 18357 : mnDescent = 0;
3434 : 18357 : mnIntLeading = 0;
3435 : 18357 : mnExtLeading = 0;
3436 : 18357 : mnSlant = 0;
3437 : 18357 : mnMinKashida = 0;
3438 : :
3439 : : // reset metrics that are usually derived from the measurements
3440 : 18357 : mnUnderlineSize = 0;
3441 : 18357 : mnUnderlineOffset = 0;
3442 : 18357 : mnBUnderlineSize = 0;
3443 : 18357 : mnBUnderlineOffset = 0;
3444 : 18357 : mnDUnderlineSize = 0;
3445 : 18357 : mnDUnderlineOffset1 = 0;
3446 : 18357 : mnDUnderlineOffset2 = 0;
3447 : 18357 : mnWUnderlineSize = 0;
3448 : 18357 : mnWUnderlineOffset = 0;
3449 : 18357 : mnAboveUnderlineSize = 0;
3450 : 18357 : mnAboveUnderlineOffset = 0;
3451 : 18357 : mnAboveBUnderlineSize = 0;
3452 : 18357 : mnAboveBUnderlineOffset = 0;
3453 : 18357 : mnAboveDUnderlineSize = 0;
3454 : 18357 : mnAboveDUnderlineOffset1 = 0;
3455 : 18357 : mnAboveDUnderlineOffset2 = 0;
3456 : 18357 : mnAboveWUnderlineSize = 0;
3457 : 18357 : mnAboveWUnderlineOffset = 0;
3458 : 18357 : mnStrikeoutSize = 0;
3459 : 18357 : mnStrikeoutOffset = 0;
3460 : 18357 : mnBStrikeoutSize = 0;
3461 : 18357 : mnBStrikeoutOffset = 0;
3462 : 18357 : mnDStrikeoutSize = 0;
3463 : 18357 : mnDStrikeoutOffset1 = 0;
3464 : 18357 : mnDStrikeoutOffset2 = 0;
3465 : 18357 : }
3466 : :
3467 : : // -----------------------------------------------------------------------
3468 : :
3469 : 7334 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
3470 : : {
3471 : 7334 : long nDescent = mnDescent;
3472 [ + + ]: 7334 : if ( nDescent <= 0 )
3473 : : {
3474 : 8 : nDescent = mnAscent / 10;
3475 [ + - ]: 8 : if ( !nDescent )
3476 : 8 : nDescent = 1;
3477 : : }
3478 : :
3479 : : // #i55341# for some fonts it is not a good idea to calculate
3480 : : // their text line metrics from the real font descent
3481 : : // => work around this problem just for these fonts
3482 [ + + ]: 7334 : if( 3*nDescent > mnAscent )
3483 : 34 : nDescent = mnAscent / 3;
3484 : :
3485 : 7334 : long nLineHeight = ((nDescent*25)+50) / 100;
3486 [ + + ]: 7334 : if ( !nLineHeight )
3487 : 118 : nLineHeight = 1;
3488 : 7334 : long nLineHeight2 = nLineHeight / 2;
3489 [ + + ]: 7334 : if ( !nLineHeight2 )
3490 : 1471 : nLineHeight2 = 1;
3491 : :
3492 : 7334 : long nBLineHeight = ((nDescent*50)+50) / 100;
3493 [ + + ]: 7334 : if ( nBLineHeight == nLineHeight )
3494 : 597 : nBLineHeight++;
3495 : 7334 : long nBLineHeight2 = nBLineHeight/2;
3496 [ + + ]: 7334 : if ( !nBLineHeight2 )
3497 : 10 : nBLineHeight2 = 1;
3498 : :
3499 : 7334 : long n2LineHeight = ((nDescent*16)+50) / 100;
3500 [ + + ]: 7334 : if ( !n2LineHeight )
3501 : 1316 : n2LineHeight = 1;
3502 : 7334 : long n2LineDY = n2LineHeight;
3503 : : /* #117909#
3504 : : * add some pixels to minimum double line distance on higher resolution devices
3505 : : */
3506 : 7334 : long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
3507 [ + + ]: 7334 : if ( n2LineDY < nMin2LineDY )
3508 : 3817 : n2LineDY = nMin2LineDY;
3509 : 7334 : long n2LineDY2 = n2LineDY/2;
3510 [ + + ]: 7334 : if ( !n2LineDY2 )
3511 : 1730 : n2LineDY2 = 1;
3512 : :
3513 : 7334 : long nUnderlineOffset = mnDescent/2 + 1;
3514 : 7334 : long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
3515 : :
3516 : 7334 : mnUnderlineSize = nLineHeight;
3517 : 7334 : mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
3518 : :
3519 : 7334 : mnBUnderlineSize = nBLineHeight;
3520 : 7334 : mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
3521 : :
3522 : 7334 : mnDUnderlineSize = n2LineHeight;
3523 : 7334 : mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
3524 : 7334 : mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
3525 : :
3526 : 7334 : long nWCalcSize = mnDescent;
3527 [ + + ]: 7334 : if ( nWCalcSize < 6 )
3528 : : {
3529 [ + + ][ + + ]: 1471 : if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
3530 : 597 : mnWUnderlineSize = nWCalcSize;
3531 : : else
3532 : 1471 : mnWUnderlineSize = 3;
3533 : : }
3534 : : else
3535 : 5863 : mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
3536 : :
3537 : : // #109280# the following line assures that wavelnes are never placed below the descent, however
3538 : : // for most fonts the waveline then is drawn into the text, so we better keep the old solution
3539 : : // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
3540 : 7334 : mnWUnderlineOffset = nUnderlineOffset;
3541 : :
3542 : 7334 : mnStrikeoutSize = nLineHeight;
3543 : 7334 : mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
3544 : :
3545 : 7334 : mnBStrikeoutSize = nBLineHeight;
3546 : 7334 : mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
3547 : :
3548 : 7334 : mnDStrikeoutSize = n2LineHeight;
3549 : 7334 : mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
3550 : 7334 : mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
3551 : 7334 : }
3552 : :
3553 : : // -----------------------------------------------------------------------
3554 : :
3555 : 7334 : void ImplFontMetricData::ImplInitAboveTextLineSize()
3556 : : {
3557 : 7334 : long nIntLeading = mnIntLeading;
3558 : : // TODO: assess usage of nLeading below (changed in extleading CWS)
3559 : : // if no leading is available, we assume 15% of the ascent
3560 [ + + ]: 7334 : if ( nIntLeading <= 0 )
3561 : : {
3562 : 261 : nIntLeading = mnAscent*15/100;
3563 [ + + ]: 261 : if ( !nIntLeading )
3564 : 38 : nIntLeading = 1;
3565 : : }
3566 : :
3567 : 7334 : long nLineHeight = ((nIntLeading*25)+50) / 100;
3568 [ + + ]: 7334 : if ( !nLineHeight )
3569 : 584 : nLineHeight = 1;
3570 : :
3571 : 7334 : long nBLineHeight = ((nIntLeading*50)+50) / 100;
3572 [ + + ]: 7334 : if ( nBLineHeight == nLineHeight )
3573 : 1427 : nBLineHeight++;
3574 : :
3575 : 7334 : long n2LineHeight = ((nIntLeading*16)+50) / 100;
3576 [ + + ]: 7334 : if ( !n2LineHeight )
3577 : 1567 : n2LineHeight = 1;
3578 : :
3579 : 7334 : long nCeiling = -mnAscent;
3580 : :
3581 : 7334 : mnAboveUnderlineSize = nLineHeight;
3582 : 7334 : mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
3583 : :
3584 : 7334 : mnAboveBUnderlineSize = nBLineHeight;
3585 : 7334 : mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
3586 : :
3587 : 7334 : mnAboveDUnderlineSize = n2LineHeight;
3588 : 7334 : mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
3589 : 7334 : mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2;
3590 : :
3591 : 7334 : long nWCalcSize = nIntLeading;
3592 [ + + ]: 7334 : if ( nWCalcSize < 6 )
3593 : : {
3594 [ + + ][ + + ]: 1910 : if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
3595 : 1427 : mnAboveWUnderlineSize = nWCalcSize;
3596 : : else
3597 : 1910 : mnAboveWUnderlineSize = 3;
3598 : : }
3599 : : else
3600 : 5424 : mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
3601 : :
3602 : 7334 : mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
3603 : 7334 : }
3604 : :
3605 : : // -----------------------------------------------------------------------
3606 : :
3607 : 436240 : static void ImplDrawWavePixel( long nOriginX, long nOriginY,
3608 : : long nCurX, long nCurY,
3609 : : short nOrientation,
3610 : : SalGraphics* pGraphics,
3611 : : OutputDevice* pOutDev,
3612 : : sal_Bool bDrawPixAsRect,
3613 : :
3614 : : long nPixWidth, long nPixHeight )
3615 : : {
3616 [ + + ]: 436240 : if ( nOrientation )
3617 : 189900 : ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
3618 : :
3619 [ + + ]: 436240 : if ( bDrawPixAsRect )
3620 : : {
3621 : :
3622 : 164150 : pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
3623 : : }
3624 : : else
3625 : : {
3626 : 272090 : pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
3627 : : }
3628 : 436240 : }
3629 : :
3630 : : // -----------------------------------------------------------------------
3631 : :
3632 : 6366 : void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
3633 : : long nDistX, long nDistY,
3634 : : long nWidth, long nHeight,
3635 : : long nLineWidth, short nOrientation,
3636 : : const Color& rColor )
3637 : : {
3638 [ + - ]: 6366 : if ( !nHeight )
3639 : 6366 : return;
3640 : :
3641 : 6366 : long nStartX = nBaseX + nDistX;
3642 : 6366 : long nStartY = nBaseY + nDistY;
3643 : :
3644 : : // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
3645 [ + + ][ + + ]: 6366 : if ( (nLineWidth == 1) && (nHeight == 1) )
3646 : : {
3647 [ + - ]: 4 : mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
3648 : 4 : mbInitLineColor = sal_True;
3649 : :
3650 : 4 : long nEndX = nStartX+nWidth;
3651 : 4 : long nEndY = nStartY;
3652 [ - + ]: 4 : if ( nOrientation )
3653 : : {
3654 : 0 : ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
3655 : 0 : ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
3656 : : }
3657 [ + - ]: 4 : mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
3658 : : }
3659 : : else
3660 : : {
3661 : 6362 : long nCurX = nStartX;
3662 : 6362 : long nCurY = nStartY;
3663 : 6362 : long nDiffX = 2;
3664 : 6362 : long nDiffY = nHeight-1;
3665 : 6362 : long nCount = nWidth;
3666 : 6362 : long nOffY = -1;
3667 : : long nFreq;
3668 : : long i;
3669 : : long nPixWidth;
3670 : : long nPixHeight;
3671 : : sal_Bool bDrawPixAsRect;
3672 : : // Auf Druckern die Pixel per DrawRect() ausgeben
3673 [ + - ][ + + ]: 6362 : if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
[ + + ]
3674 : : {
3675 [ + + ][ + + ]: 2386 : if ( mbLineColor || mbInitLineColor )
3676 : : {
3677 [ + - ]: 2291 : mpGraphics->SetLineColor();
3678 : 2291 : mbInitLineColor = sal_True;
3679 : : }
3680 [ + - ]: 2386 : mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
3681 : 2386 : mbInitFillColor = sal_True;
3682 : 2386 : bDrawPixAsRect = sal_True;
3683 : 2386 : nPixWidth = nLineWidth;
3684 : 2386 : nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
3685 : : }
3686 : : else
3687 : : {
3688 [ + - ]: 3976 : mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
3689 : 3976 : mbInitLineColor = sal_True;
3690 : 3976 : nPixWidth = 1;
3691 : 3976 : nPixHeight = 1;
3692 : 3976 : bDrawPixAsRect = sal_False;
3693 : : }
3694 : :
3695 [ - + ]: 6362 : if ( !nDiffY )
3696 : : {
3697 [ # # ]: 0 : while ( nWidth )
3698 : : {
3699 : : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3700 : : mpGraphics, this,
3701 [ # # ]: 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
3702 : 0 : nCurX++;
3703 : 0 : nWidth--;
3704 : : }
3705 : : }
3706 : : else
3707 : : {
3708 : 6362 : nCurY += nDiffY;
3709 : 6362 : nFreq = nCount / (nDiffX+nDiffY);
3710 [ + + ]: 98247 : while ( nFreq-- )
3711 : : {
3712 [ + + ]: 331592 : for( i = nDiffY; i; --i )
3713 : : {
3714 : : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3715 : : mpGraphics, this,
3716 [ + - ]: 239707 : bDrawPixAsRect, nPixWidth, nPixHeight );
3717 : 239707 : nCurX++;
3718 : 239707 : nCurY += nOffY;
3719 : : }
3720 [ + + ]: 275655 : for( i = nDiffX; i; --i )
3721 : : {
3722 : : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3723 : : mpGraphics, this,
3724 [ + - ]: 183770 : bDrawPixAsRect, nPixWidth, nPixHeight );
3725 : 183770 : nCurX++;
3726 : : }
3727 : 91885 : nOffY = -nOffY;
3728 : : }
3729 : 6362 : nFreq = nCount % (nDiffX+nDiffY);
3730 [ + + ]: 6362 : if ( nFreq )
3731 : : {
3732 [ + + ][ + + ]: 15907 : for( i = nDiffY; i && nFreq; --i, --nFreq )
[ + + ]
3733 : : {
3734 : : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3735 : : mpGraphics, this,
3736 [ + - ]: 11043 : bDrawPixAsRect, nPixWidth, nPixHeight );
3737 : 11043 : nCurX++;
3738 : 11043 : nCurY += nOffY;
3739 : :
3740 : : }
3741 [ + - ][ + + ]: 8086 : for( i = nDiffX; i && nFreq; --i, --nFreq )
[ + + ]
3742 : : {
3743 : : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3744 : : mpGraphics, this,
3745 [ + - ]: 1720 : bDrawPixAsRect, nPixWidth, nPixHeight );
3746 : 1720 : nCurX++;
3747 : : }
3748 : : }
3749 : : }
3750 : :
3751 : : }
3752 : : }
3753 : :
3754 : : // -----------------------------------------------------------------------
3755 : :
3756 : 2386 : void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
3757 : : long nDistX, long nDistY, long nWidth,
3758 : : FontUnderline eTextLine,
3759 : : Color aColor,
3760 : : sal_Bool bIsAbove )
3761 : : {
3762 : 2386 : ImplFontEntry* pFontEntry = mpFontEntry;
3763 : : long nLineHeight;
3764 : : long nLinePos;
3765 : :
3766 [ - + ]: 2386 : if ( bIsAbove )
3767 : : {
3768 : 0 : nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
3769 : 0 : nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
3770 : : }
3771 : : else
3772 : : {
3773 : 2386 : nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
3774 : 2386 : nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
3775 : : }
3776 [ - + ][ # # ]: 2386 : if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
3777 : 0 : nLineHeight = 3;
3778 : 2386 : long nLineWidth = (mnDPIX/300);
3779 [ + - ]: 2386 : if ( !nLineWidth )
3780 : 2386 : nLineWidth = 1;
3781 [ + - ]: 2386 : if ( eTextLine == UNDERLINE_BOLDWAVE )
3782 : 2386 : nLineWidth *= 2;
3783 : 2386 : nLinePos += nDistY - (nLineHeight / 2);
3784 : 2386 : long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
3785 [ - + ]: 2386 : if ( eTextLine == UNDERLINE_DOUBLEWAVE )
3786 : : {
3787 : 0 : long nOrgLineHeight = nLineHeight;
3788 : 0 : nLineHeight /= 3;
3789 [ # # ]: 0 : if ( nLineHeight < 2 )
3790 : : {
3791 [ # # ]: 0 : if ( nOrgLineHeight > 1 )
3792 : 0 : nLineHeight = 2;
3793 : : else
3794 : 0 : nLineHeight = 1;
3795 : : }
3796 : 0 : long nLineDY = nOrgLineHeight-(nLineHeight*2);
3797 [ # # ]: 0 : if ( nLineDY < nLineWidthHeight )
3798 : 0 : nLineDY = nLineWidthHeight;
3799 : 0 : long nLineDY2 = nLineDY/2;
3800 [ # # ]: 0 : if ( !nLineDY2 )
3801 : 0 : nLineDY2 = 1;
3802 : :
3803 : 0 : nLinePos -= nLineWidthHeight-nLineDY2;
3804 : : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3805 : 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
3806 : 0 : nLinePos += nLineWidthHeight+nLineDY;
3807 : : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3808 : 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
3809 : : }
3810 : : else
3811 : : {
3812 : 2386 : nLinePos -= nLineWidthHeight/2;
3813 : : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3814 : 2386 : nLineWidth, mpFontEntry->mnOrientation, aColor );
3815 : : }
3816 : 2386 : }
3817 : :
3818 : : // -----------------------------------------------------------------------
3819 : :
3820 : 58594 : void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
3821 : : long nDistX, long nDistY, long nWidth,
3822 : : FontUnderline eTextLine,
3823 : : Color aColor,
3824 : : sal_Bool bIsAbove )
3825 : : {
3826 : 58594 : ImplFontEntry* pFontEntry = mpFontEntry;
3827 : 58594 : long nLineHeight = 0;
3828 : 58594 : long nLinePos = 0;
3829 : 58594 : long nLinePos2 = 0;
3830 : :
3831 : 58594 : const long nY = nDistY;
3832 : :
3833 [ + + ]: 58594 : if ( eTextLine > UNDERLINE_LAST )
3834 : 864 : eTextLine = UNDERLINE_SINGLE;
3835 : :
3836 [ + + + + ]: 58594 : switch ( eTextLine )
3837 : : {
3838 : : case UNDERLINE_SINGLE:
3839 : : case UNDERLINE_DOTTED:
3840 : : case UNDERLINE_DASH:
3841 : : case UNDERLINE_LONGDASH:
3842 : : case UNDERLINE_DASHDOT:
3843 : : case UNDERLINE_DASHDOTDOT:
3844 [ + + ]: 28988 : if ( bIsAbove )
3845 : : {
3846 : 5456 : nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
3847 : 5456 : nLinePos = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
3848 : : }
3849 : : else
3850 : : {
3851 : 23532 : nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
3852 : 23532 : nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
3853 : : }
3854 : 28988 : break;
3855 : : case UNDERLINE_BOLD:
3856 : : case UNDERLINE_BOLDDOTTED:
3857 : : case UNDERLINE_BOLDDASH:
3858 : : case UNDERLINE_BOLDLONGDASH:
3859 : : case UNDERLINE_BOLDDASHDOT:
3860 : : case UNDERLINE_BOLDDASHDOTDOT:
3861 [ - + ]: 1290 : if ( bIsAbove )
3862 : : {
3863 : 0 : nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
3864 : 0 : nLinePos = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
3865 : : }
3866 : : else
3867 : : {
3868 : 1290 : nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
3869 : 1290 : nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
3870 : : }
3871 : 1290 : break;
3872 : : case UNDERLINE_DOUBLE:
3873 [ + + ]: 5454 : if ( bIsAbove )
3874 : : {
3875 : 2604 : nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
3876 : 2604 : nLinePos = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
3877 : 2604 : nLinePos2 = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
3878 : : }
3879 : : else
3880 : : {
3881 : 2850 : nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
3882 : 2850 : nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
3883 : 2850 : nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
3884 : : }
3885 : 5454 : break;
3886 : : default:
3887 : 22862 : break;
3888 : : }
3889 : :
3890 [ + + ]: 58594 : if ( nLineHeight )
3891 : : {
3892 [ + + ][ + + ]: 35732 : if ( mbLineColor || mbInitLineColor )
3893 : : {
3894 : 30719 : mpGraphics->SetLineColor();
3895 : 30719 : mbInitLineColor = sal_True;
3896 : : }
3897 : 35732 : mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
3898 : 35732 : mbInitFillColor = sal_True;
3899 : :
3900 : 35732 : long nLeft = nDistX;
3901 : :
3902 [ + + + + : 35732 : switch ( eTextLine )
- + - ]
3903 : : {
3904 : : case UNDERLINE_SINGLE:
3905 : : case UNDERLINE_BOLD:
3906 : 25536 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3907 : 25536 : break;
3908 : : case UNDERLINE_DOUBLE:
3909 : 5454 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3910 : 5454 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
3911 : 5454 : break;
3912 : : case UNDERLINE_DOTTED:
3913 : : case UNDERLINE_BOLDDOTTED:
3914 : : {
3915 : 2564 : long nDotWidth = nLineHeight*mnDPIY;
3916 : 2564 : nDotWidth += mnDPIY/2;
3917 : 2564 : nDotWidth /= mnDPIY;
3918 : 2564 : long nTempWidth = nDotWidth;
3919 : 2564 : long nEnd = nLeft+nWidth;
3920 [ + + ]: 34776 : while ( nLeft < nEnd )
3921 : : {
3922 [ + + ]: 32212 : if ( nLeft+nTempWidth > nEnd )
3923 : 922 : nTempWidth = nEnd-nLeft;
3924 : 32212 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
3925 : 32212 : nLeft += nDotWidth*2;
3926 : : }
3927 : : }
3928 : 2564 : break;
3929 : : case UNDERLINE_DASH:
3930 : : case UNDERLINE_LONGDASH:
3931 : : case UNDERLINE_BOLDDASH:
3932 : : case UNDERLINE_BOLDLONGDASH:
3933 : : {
3934 : 888 : long nDotWidth = nLineHeight*mnDPIY;
3935 : 888 : nDotWidth += mnDPIY/2;
3936 : 888 : nDotWidth /= mnDPIY;
3937 : : long nMinDashWidth;
3938 : : long nMinSpaceWidth;
3939 : : long nSpaceWidth;
3940 : : long nDashWidth;
3941 [ + + ][ - + ]: 888 : if ( (eTextLine == UNDERLINE_LONGDASH) ||
3942 : : (eTextLine == UNDERLINE_BOLDLONGDASH) )
3943 : : {
3944 : 516 : nMinDashWidth = nDotWidth*6;
3945 : 516 : nMinSpaceWidth = nDotWidth*2;
3946 : 516 : nDashWidth = 200;
3947 : 516 : nSpaceWidth = 100;
3948 : : }
3949 : : else
3950 : : {
3951 : 372 : nMinDashWidth = nDotWidth*4;
3952 : 372 : nMinSpaceWidth = (nDotWidth*150)/100;
3953 : 372 : nDashWidth = 100;
3954 : 372 : nSpaceWidth = 50;
3955 : : }
3956 : 888 : nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
3957 : 888 : nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
3958 : : // DashWidth wird gegebenenfalls verbreitert, wenn
3959 : : // die dicke der Linie im Verhaeltnis zur Laenge
3960 : : // zu dick wird
3961 [ + + ]: 888 : if ( nDashWidth < nMinDashWidth )
3962 : 680 : nDashWidth = nMinDashWidth;
3963 [ + + ]: 888 : if ( nSpaceWidth < nMinSpaceWidth )
3964 : 680 : nSpaceWidth = nMinSpaceWidth;
3965 : 888 : long nTempWidth = nDashWidth;
3966 : 888 : long nEnd = nLeft+nWidth;
3967 [ + + ]: 1780 : while ( nLeft < nEnd )
3968 : : {
3969 [ + + ]: 892 : if ( nLeft+nTempWidth > nEnd )
3970 : 864 : nTempWidth = nEnd-nLeft;
3971 : 892 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
3972 : 892 : nLeft += nDashWidth+nSpaceWidth;
3973 : : }
3974 : : }
3975 : 888 : break;
3976 : : case UNDERLINE_DASHDOT:
3977 : : case UNDERLINE_BOLDDASHDOT:
3978 : : {
3979 : 0 : long nDotWidth = nLineHeight*mnDPIY;
3980 : 0 : nDotWidth += mnDPIY/2;
3981 : 0 : nDotWidth /= mnDPIY;
3982 : 0 : long nDashWidth = ((100*mnDPIX)+1270)/2540;
3983 : 0 : long nMinDashWidth = nDotWidth*4;
3984 : : // DashWidth wird gegebenenfalls verbreitert, wenn
3985 : : // die dicke der Linie im Verhaeltnis zur Laenge
3986 : : // zu dick wird
3987 [ # # ]: 0 : if ( nDashWidth < nMinDashWidth )
3988 : 0 : nDashWidth = nMinDashWidth;
3989 : 0 : long nTempDotWidth = nDotWidth;
3990 : 0 : long nTempDashWidth = nDashWidth;
3991 : 0 : long nEnd = nLeft+nWidth;
3992 [ # # ]: 0 : while ( nLeft < nEnd )
3993 : : {
3994 [ # # ]: 0 : if ( nLeft+nTempDotWidth > nEnd )
3995 : 0 : nTempDotWidth = nEnd-nLeft;
3996 : 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
3997 : 0 : nLeft += nDotWidth*2;
3998 [ # # ]: 0 : if ( nLeft > nEnd )
3999 : 0 : break;
4000 [ # # ]: 0 : if ( nLeft+nTempDashWidth > nEnd )
4001 : 0 : nTempDashWidth = nEnd-nLeft;
4002 : 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
4003 : 0 : nLeft += nDashWidth+nDotWidth;
4004 : : }
4005 : : }
4006 : 0 : break;
4007 : : case UNDERLINE_DASHDOTDOT:
4008 : : case UNDERLINE_BOLDDASHDOTDOT:
4009 : : {
4010 : 1290 : long nDotWidth = nLineHeight*mnDPIY;
4011 : 1290 : nDotWidth += mnDPIY/2;
4012 : 1290 : nDotWidth /= mnDPIY;
4013 : 1290 : long nDashWidth = ((100*mnDPIX)+1270)/2540;
4014 : 1290 : long nMinDashWidth = nDotWidth*4;
4015 : : // DashWidth wird gegebenenfalls verbreitert, wenn
4016 : : // die dicke der Linie im Verhaeltnis zur Laenge
4017 : : // zu dick wird
4018 [ + - ]: 1290 : if ( nDashWidth < nMinDashWidth )
4019 : 1290 : nDashWidth = nMinDashWidth;
4020 : 1290 : long nTempDotWidth = nDotWidth;
4021 : 1290 : long nTempDashWidth = nDashWidth;
4022 : 1290 : long nEnd = nLeft+nWidth;
4023 [ + + ]: 3434 : while ( nLeft < nEnd )
4024 : : {
4025 [ + + ]: 2637 : if ( nLeft+nTempDotWidth > nEnd )
4026 : 94 : nTempDotWidth = nEnd-nLeft;
4027 : 2637 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
4028 : 2637 : nLeft += nDotWidth*2;
4029 [ + + ]: 2637 : if ( nLeft > nEnd )
4030 : 177 : break;
4031 [ + + ]: 2460 : if ( nLeft+nTempDotWidth > nEnd )
4032 : 216 : nTempDotWidth = nEnd-nLeft;
4033 : 2460 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
4034 : 2460 : nLeft += nDotWidth*2;
4035 [ + + ]: 2460 : if ( nLeft > nEnd )
4036 : 316 : break;
4037 [ + + ]: 2144 : if ( nLeft+nTempDashWidth > nEnd )
4038 : 633 : nTempDashWidth = nEnd-nLeft;
4039 : 2144 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
4040 : 2144 : nLeft += nDashWidth+nDotWidth;
4041 : : }
4042 : : }
4043 : 1290 : break;
4044 : : default:
4045 : 35732 : break;
4046 : : }
4047 : : }
4048 : 58594 : }
4049 : :
4050 : : // -----------------------------------------------------------------------
4051 : :
4052 : 28816 : void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
4053 : : long nDistX, long nDistY, long nWidth,
4054 : : FontStrikeout eStrikeout,
4055 : : Color aColor )
4056 : : {
4057 : 28816 : ImplFontEntry* pFontEntry = mpFontEntry;
4058 : 28816 : long nLineHeight = 0;
4059 : 28816 : long nLinePos = 0;
4060 : 28816 : long nLinePos2 = 0;
4061 : :
4062 : 28816 : long nY = nDistY;
4063 : :
4064 [ + + ]: 28816 : if ( eStrikeout > STRIKEOUT_LAST )
4065 : 3430 : eStrikeout = STRIKEOUT_SINGLE;
4066 : :
4067 [ + + + + ]: 28816 : switch ( eStrikeout )
4068 : : {
4069 : : case STRIKEOUT_SINGLE:
4070 : 5890 : nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
4071 : 5890 : nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
4072 : 5890 : break;
4073 : : case STRIKEOUT_BOLD:
4074 : 324 : nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
4075 : 324 : nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
4076 : 324 : break;
4077 : : case STRIKEOUT_DOUBLE:
4078 : 2520 : nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
4079 : 2520 : nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
4080 : 2520 : nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
4081 : 2520 : break;
4082 : : default:
4083 : 20082 : break;
4084 : : }
4085 : :
4086 [ + + ]: 28816 : if ( nLineHeight )
4087 : : {
4088 [ + + ][ + + ]: 8734 : if ( mbLineColor || mbInitLineColor )
4089 : : {
4090 : 7356 : mpGraphics->SetLineColor();
4091 : 7356 : mbInitLineColor = sal_True;
4092 : : }
4093 : 8734 : mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
4094 : 8734 : mbInitFillColor = sal_True;
4095 : :
4096 : 8734 : const long& nLeft = nDistX;
4097 : :
4098 [ + + - ]: 8734 : switch ( eStrikeout )
4099 : : {
4100 : : case STRIKEOUT_SINGLE:
4101 : : case STRIKEOUT_BOLD:
4102 : 6214 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
4103 : 6214 : break;
4104 : : case STRIKEOUT_DOUBLE:
4105 : 2520 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
4106 : 2520 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
4107 : 2520 : break;
4108 : : default:
4109 : 8734 : break;
4110 : : }
4111 : : }
4112 : 28816 : }
4113 : :
4114 : : // -----------------------------------------------------------------------
4115 : :
4116 : 1674 : void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
4117 : : long nDistX, long nDistY, long nWidth,
4118 : : FontStrikeout eStrikeout,
4119 : : Color aColor )
4120 : : {
4121 : : //See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
4122 : : //to tweak this
4123 [ + - ]: 1674 : if (!nWidth)
4124 : : return;
4125 : :
4126 : : // PDF-export does its own strikeout drawing... why again?
4127 [ - + ][ # # ]: 1674 : if( mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) )
[ # # ][ + - ]
4128 : : return;
4129 : :
4130 : : // prepare string for strikeout measurement
4131 : : static char cStrikeoutChar;
4132 [ + + ]: 1674 : if ( eStrikeout == STRIKEOUT_SLASH )
4133 : 564 : cStrikeoutChar = '/';
4134 : : else // ( eStrikeout == STRIKEOUT_X )
4135 : 1110 : cStrikeoutChar = 'X';
4136 : : static const int nTestStrLen = 4;
4137 : : static const int nMaxStrikeStrLen = 2048;
4138 : : xub_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
4139 [ + + ]: 8370 : for( int i = 0; i < nTestStrLen; ++i)
4140 : 6696 : aChars[i] = cStrikeoutChar;
4141 : 1674 : const rtl::OUString aStrikeoutTest(aChars, nTestStrLen);
4142 : :
4143 : : // calculate approximation of strikeout atom size
4144 : 1674 : long nStrikeoutWidth = 0;
4145 [ + - ][ + - ]: 1674 : SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
[ + - ]
4146 [ + - ]: 1674 : if( pLayout )
4147 : : {
4148 [ + - ]: 1674 : nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
4149 [ + - ]: 1674 : pLayout->Release();
4150 : : }
4151 [ + + ]: 1674 : if( nStrikeoutWidth <= 0 ) // sanity check
4152 : : return;
4153 : :
4154 : 1598 : int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
4155 [ - + ]: 1598 : if( nStrikeStrLen > nMaxStrikeStrLen )
4156 : 0 : nStrikeStrLen = nMaxStrikeStrLen;
4157 : :
4158 : : // build the strikeout string
4159 [ + + ]: 8284 : for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
4160 : 6686 : aChars[i] = cStrikeoutChar;
4161 : 1598 : const rtl::OUString aStrikeoutText(aChars, nStrikeStrLen);
4162 : :
4163 [ + - ]: 1598 : if( mpFontEntry->mnOrientation )
4164 : 1598 : ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
4165 : 1598 : nBaseX += nDistX;
4166 : 1598 : nBaseY += nDistY;
4167 : :
4168 : : // strikeout text has to be left aligned
4169 : 1598 : sal_uLong nOrigTLM = mnTextLayoutMode;
4170 : 1598 : mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
4171 [ + - ][ + - ]: 1598 : pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN );
[ + - ]
4172 : 1598 : mnTextLayoutMode = nOrigTLM;
4173 : :
4174 [ - + ]: 1598 : if( !pLayout )
4175 : : return;
4176 : :
4177 : : // draw the strikeout text
4178 : 1598 : const Color aOldColor = GetTextColor();
4179 [ + - ]: 1598 : SetTextColor( aColor );
4180 [ + - ]: 1598 : ImplInitTextColor();
4181 : :
4182 : 1598 : pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
4183 : :
4184 [ + - ]: 1598 : Rectangle aPixelRect;
4185 : 1598 : aPixelRect.nLeft = nBaseX+mnTextOffX;
4186 : 1598 : aPixelRect.nRight = aPixelRect.nLeft+nWidth;
4187 : 1598 : aPixelRect.nBottom = nBaseY+mpFontEntry->maMetric.mnDescent;
4188 : 1598 : aPixelRect.nTop = nBaseY-mpFontEntry->maMetric.mnAscent;
4189 : :
4190 [ + - ]: 1598 : if (mpFontEntry->mnOrientation)
4191 : : {
4192 [ + - ]: 1598 : Polygon aPoly( aPixelRect );
4193 [ + - ]: 1598 : aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
4194 [ + - ][ + - ]: 1598 : aPixelRect = aPoly.GetBoundRect();
4195 : : }
4196 : :
4197 [ + - ]: 1598 : Push( PUSH_CLIPREGION );
4198 [ + - ][ + - ]: 1598 : IntersectClipRegion( PixelToLogic(aPixelRect) );
4199 [ + - ]: 1598 : if( mbInitClipRegion )
4200 [ + - ]: 1598 : ImplInitClipRegion();
4201 : :
4202 [ + - ]: 1598 : pLayout->DrawText( *mpGraphics );
4203 : :
4204 [ + - ]: 1598 : pLayout->Release();
4205 [ + - ]: 1598 : Pop();
4206 : :
4207 [ + - ]: 1598 : SetTextColor( aOldColor );
4208 [ + - ][ - + ]: 1674 : ImplInitTextColor();
[ + + ]
4209 : : }
4210 : :
4211 : : // -----------------------------------------------------------------------
4212 : :
4213 : 30502 : void OutputDevice::ImplDrawTextLine( long nX, long nY,
4214 : : long nDistX, long nWidth,
4215 : : FontStrikeout eStrikeout,
4216 : : FontUnderline eUnderline,
4217 : : FontUnderline eOverline,
4218 : : sal_Bool bUnderlineAbove )
4219 : : {
4220 [ + + ]: 30502 : if ( !nWidth )
4221 : 30502 : return;
4222 : :
4223 : 30490 : Color aStrikeoutColor = GetTextColor();
4224 : 30490 : Color aUnderlineColor = GetTextLineColor();
4225 : 30490 : Color aOverlineColor = GetOverlineColor();
4226 : 30490 : sal_Bool bStrikeoutDone = sal_False;
4227 : 30490 : sal_Bool bUnderlineDone = sal_False;
4228 : 30490 : sal_Bool bOverlineDone = sal_False;
4229 : :
4230 [ + + ]: 30490 : if ( IsRTLEnabled() )
4231 : : {
4232 : : // --- RTL --- mirror at basex
4233 : 198 : long nXAdd = nWidth - nDistX;
4234 [ + - ]: 198 : if( mpFontEntry->mnOrientation )
4235 : 198 : nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
4236 : 198 : nX += nXAdd - 1;
4237 : : }
4238 : :
4239 [ + + ]: 30490 : if ( !IsTextLineColor() )
4240 : 17265 : aUnderlineColor = GetTextColor();
4241 : :
4242 [ + + ]: 30490 : if ( !IsOverlineColor() )
4243 : 18412 : aOverlineColor = GetTextColor();
4244 : :
4245 [ + - ][ + - ]: 30490 : if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
[ + - ][ + + ]
4246 : : (eUnderline == UNDERLINE_WAVE) ||
4247 : : (eUnderline == UNDERLINE_DOUBLEWAVE) ||
4248 : : (eUnderline == UNDERLINE_BOLDWAVE) )
4249 : : {
4250 [ + - ]: 2386 : ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
4251 : 2386 : bUnderlineDone = sal_True;
4252 : : }
4253 [ + - ][ + - ]: 30490 : if ( (eOverline == UNDERLINE_SMALLWAVE) ||
[ + - ][ - + ]
4254 : : (eOverline == UNDERLINE_WAVE) ||
4255 : : (eOverline == UNDERLINE_DOUBLEWAVE) ||
4256 : : (eOverline == UNDERLINE_BOLDWAVE) )
4257 : : {
4258 [ # # ]: 0 : ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
4259 : 0 : bOverlineDone = sal_True;
4260 : : }
4261 : :
4262 [ + + ][ + + ]: 30490 : if ( (eStrikeout == STRIKEOUT_SLASH) ||
4263 : : (eStrikeout == STRIKEOUT_X) )
4264 : : {
4265 [ + - ]: 1674 : ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
4266 : 1674 : bStrikeoutDone = sal_True;
4267 : : }
4268 : :
4269 [ + + ]: 30490 : if ( !bUnderlineDone )
4270 [ + - ]: 28104 : ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
4271 : :
4272 [ + - ]: 30490 : if ( !bOverlineDone )
4273 [ + - ]: 30490 : ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
4274 : :
4275 [ + + ]: 30490 : if ( !bStrikeoutDone )
4276 [ + - ]: 30502 : ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
4277 : : }
4278 : :
4279 : : // -----------------------------------------------------------------------
4280 : :
4281 : 15446 : void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
4282 : : FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, sal_Bool bWordLine, sal_Bool bUnderlineAbove )
4283 : : {
4284 [ + + ]: 15446 : if( bWordLine )
4285 : : {
4286 : : // draw everything relative to the layout base point
4287 : 7938 : const Point aStartPt = rSalLayout.DrawBase();
4288 : : // calculate distance of each word from the base point
4289 : 7938 : Point aPos;
4290 : 7938 : sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
4291 : 47309 : for( int nStart = 0;;)
4292 : : {
4293 : : // iterate through the layouted glyphs
4294 : : sal_GlyphId nGlyphIndex;
4295 [ + - ][ + + ]: 47309 : if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
4296 : : break;
4297 : :
4298 : : // calculate the boundaries of each word
4299 [ + - ][ + + ]: 39371 : if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
4300 : : {
4301 [ + + ]: 37512 : if( !nWidth )
4302 : : {
4303 : : // get the distance to the base point (as projected to baseline)
4304 : 9200 : nDist = aPos.X() - aStartPt.X();
4305 [ + + ]: 9200 : if( mpFontEntry->mnOrientation )
4306 : : {
4307 : 3986 : const long nDY = aPos.Y() - aStartPt.Y();
4308 : 3986 : const double fRad = mpFontEntry->mnOrientation * F_PI1800;
4309 : 3986 : nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
4310 : : }
4311 : : }
4312 : :
4313 : : // update the length of the textline
4314 : 37512 : nWidth += nAdvance;
4315 : : }
4316 [ + + ]: 1859 : else if( nWidth > 0 )
4317 : : {
4318 : : // draw the textline for each word
4319 : : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
4320 [ + - ]: 1731 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4321 : 1731 : nWidth = 0;
4322 : : }
4323 : : }
4324 : :
4325 : : // draw textline for the last word
4326 [ + + ]: 7938 : if( nWidth > 0 )
4327 : : {
4328 : : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
4329 [ + - ]: 7938 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4330 : : }
4331 : : }
4332 : : else
4333 : : {
4334 [ + - ]: 7508 : Point aStartPt = rSalLayout.GetDrawPosition();
4335 [ + - ]: 7508 : int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
4336 : 7508 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
4337 [ + - ]: 7508 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4338 : : }
4339 : 15446 : }
4340 : :
4341 : : // -----------------------------------------------------------------------
4342 : :
4343 : 13794 : void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
4344 : : {
4345 : 13794 : long nBaseX = nX;
4346 [ - + ]: 13794 : if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
4347 : : {
4348 : : // --- RTL ---
4349 : : // add some strange offset
4350 : 0 : nX += 2;
4351 : : // revert the hack that will be done later in ImplDrawTextLine
4352 : 0 : nX = nBaseX - nWidth - (nX - nBaseX - 1);
4353 : : }
4354 : :
4355 : 13794 : ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False );
4356 : 13794 : }
4357 : :
4358 : : // -----------------------------------------------------------------------
4359 : :
4360 : 14460 : void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, sal_Bool& rPolyLine,
4361 : : Rectangle& rRect1, Rectangle& rRect2,
4362 : : long& rYOff, long& rWidth,
4363 : : FontEmphasisMark eEmphasis,
4364 : : long nHeight, short /*nOrient*/ )
4365 : : {
4366 : : static const sal_uInt8 aAccentPolyFlags[24] =
4367 : : {
4368 : : 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
4369 : : };
4370 : :
4371 : : static const long aAccentPos[48] =
4372 : : {
4373 : : 78, 0,
4374 : : 348, 79,
4375 : : 599, 235,
4376 : : 843, 469,
4377 : : 938, 574,
4378 : : 990, 669,
4379 : : 990, 773,
4380 : : 990, 843,
4381 : : 964, 895,
4382 : : 921, 947,
4383 : : 886, 982,
4384 : : 860, 999,
4385 : : 825, 999,
4386 : : 764, 999,
4387 : : 721, 964,
4388 : : 686, 895,
4389 : : 625, 791,
4390 : : 556, 660,
4391 : : 469, 504,
4392 : : 400, 400,
4393 : : 261, 252,
4394 : : 61, 61,
4395 : : 0, 27,
4396 : : 9, 0
4397 : : };
4398 : :
4399 : 14460 : rWidth = 0;
4400 : 14460 : rYOff = 0;
4401 : 14460 : rPolyLine = sal_False;
4402 : :
4403 [ - + ]: 14460 : if ( !nHeight )
4404 : 14460 : return;
4405 : :
4406 : 14460 : FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
4407 : 14460 : long nDotSize = 0;
4408 [ + + + + : 14460 : switch ( nEmphasisStyle )
- ]
4409 : : {
4410 : : case EMPHASISMARK_DOT:
4411 : : // Dot has 55% of the height
4412 : 4186 : nDotSize = (nHeight*550)/1000;
4413 [ + + ]: 4186 : if ( !nDotSize )
4414 : 368 : nDotSize = 1;
4415 [ + + ]: 4186 : if ( nDotSize <= 2 )
4416 [ + - ]: 2480 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4417 : : else
4418 : : {
4419 : 1706 : long nRad = nDotSize/2;
4420 [ + - ]: 1706 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4421 [ + - ][ + - ]: 1706 : rPolyPoly.Insert( aPoly );
4422 : : }
4423 : 4186 : rYOff = ((nHeight*250)/1000)/2; // Center to the anthoer EmphasisMarks
4424 : 4186 : rWidth = nDotSize;
4425 : 4186 : break;
4426 : :
4427 : : case EMPHASISMARK_CIRCLE:
4428 : : // Dot has 80% of the height
4429 : 5578 : nDotSize = (nHeight*800)/1000;
4430 [ + + ]: 5578 : if ( !nDotSize )
4431 : 176 : nDotSize = 1;
4432 [ + + ]: 5578 : if ( nDotSize <= 2 )
4433 [ + - ]: 938 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4434 : : else
4435 : : {
4436 : 4640 : long nRad = nDotSize/2;
4437 [ + - ]: 4640 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4438 [ + - ]: 4640 : rPolyPoly.Insert( aPoly );
4439 : : // BorderWidth is 15%
4440 : 4640 : long nBorder = (nDotSize*150)/1000;
4441 [ + - ]: 4640 : if ( nBorder <= 1 )
4442 : 4640 : rPolyLine = sal_True;
4443 : : else
4444 : : {
4445 : : Polygon aPoly2( Point( nRad, nRad ),
4446 [ # # ]: 0 : nRad-nBorder, nRad-nBorder );
4447 [ # # ][ # # ]: 0 : rPolyPoly.Insert( aPoly2 );
4448 [ + - ]: 4640 : }
4449 : : }
4450 : 5578 : rWidth = nDotSize;
4451 : 5578 : break;
4452 : :
4453 : : case EMPHASISMARK_DISC:
4454 : : // Dot has 80% of the height
4455 : 3898 : nDotSize = (nHeight*800)/1000;
4456 [ - + ]: 3898 : if ( !nDotSize )
4457 : 0 : nDotSize = 1;
4458 [ - + ]: 3898 : if ( nDotSize <= 2 )
4459 [ # # ]: 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4460 : : else
4461 : : {
4462 : 3898 : long nRad = nDotSize/2;
4463 [ + - ]: 3898 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4464 [ + - ][ + - ]: 3898 : rPolyPoly.Insert( aPoly );
4465 : : }
4466 : 3898 : rWidth = nDotSize;
4467 : 3898 : break;
4468 : :
4469 : : case EMPHASISMARK_ACCENT:
4470 : : // Dot has 80% of the height
4471 : 798 : nDotSize = (nHeight*800)/1000;
4472 [ - + ]: 798 : if ( !nDotSize )
4473 : 0 : nDotSize = 1;
4474 [ - + ]: 798 : if ( nDotSize <= 2 )
4475 : : {
4476 [ # # ]: 0 : if ( nDotSize == 1 )
4477 : : {
4478 [ # # ]: 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4479 : 0 : rWidth = nDotSize;
4480 : : }
4481 : : else
4482 : : {
4483 [ # # ]: 0 : rRect1 = Rectangle( Point(), Size( 1, 1 ) );
4484 [ # # ]: 0 : rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
4485 : : }
4486 : : }
4487 : : else
4488 : : {
4489 : : Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
4490 : : (const Point*)aAccentPos,
4491 [ + - ]: 798 : aAccentPolyFlags );
4492 : 798 : double dScale = ((double)nDotSize)/1000.0;
4493 [ + - ]: 798 : aPoly.Scale( dScale, dScale );
4494 [ + - ]: 798 : Polygon aTemp;
4495 [ + - ]: 798 : aPoly.AdaptiveSubdivide( aTemp );
4496 [ + - ]: 798 : Rectangle aBoundRect = aTemp.GetBoundRect();
4497 [ + - ]: 798 : rWidth = aBoundRect.GetWidth();
4498 [ + - ]: 798 : nDotSize = aBoundRect.GetHeight();
4499 [ + - ][ + - ]: 798 : rPolyPoly.Insert( aTemp );
[ + - ]
4500 : : }
4501 : 798 : break;
4502 : : }
4503 : :
4504 : : // calculate position
4505 : 14460 : long nOffY = 1+(mnDPIY/300); // one visible pixel space
4506 : 14460 : long nSpaceY = nHeight-nDotSize;
4507 [ + + ]: 14460 : if ( nSpaceY >= nOffY*2 )
4508 : 10542 : rYOff += nOffY;
4509 [ + - ]: 14460 : if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
4510 : 14460 : rYOff += nDotSize;
4511 : : }
4512 : :
4513 : : // -----------------------------------------------------------------------
4514 : :
4515 : 66998 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
4516 : : const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
4517 : : const Rectangle& rRect1, const Rectangle& rRect2 )
4518 : : {
4519 [ + + ]: 66998 : if( IsRTLEnabled() )
4520 : : // --- RTL --- mirror at basex
4521 : 570 : nX = nBaseX - (nX - nBaseX - 1);
4522 : :
4523 : 66998 : nX -= mnOutOffX;
4524 : 66998 : nY -= mnOutOffY;
4525 : :
4526 [ + + ]: 66998 : if ( rPolyPoly.Count() )
4527 : : {
4528 [ + + ]: 51400 : if ( bPolyLine )
4529 : : {
4530 [ + - ][ + - ]: 21014 : Polygon aPoly = rPolyPoly.GetObject( 0 );
4531 [ + - ]: 21014 : aPoly.Move( nX, nY );
4532 [ + - ][ + - ]: 21014 : DrawPolyLine( aPoly );
4533 : : }
4534 : : else
4535 : : {
4536 [ + - ]: 30386 : PolyPolygon aPolyPoly = rPolyPoly;
4537 [ + - ]: 30386 : aPolyPoly.Move( nX, nY );
4538 [ + - ][ + - ]: 30386 : DrawPolyPolygon( aPolyPoly );
4539 : : }
4540 : : }
4541 : :
4542 [ + + ]: 66998 : if ( !rRect1.IsEmpty() )
4543 : : {
4544 : 15598 : Rectangle aRect( Point( nX+rRect1.Left(),
4545 [ + - ][ + - ]: 31196 : nY+rRect1.Top() ), rRect1.GetSize() );
4546 [ + - ]: 15598 : DrawRect( aRect );
4547 : : }
4548 : :
4549 [ - + ]: 66998 : if ( !rRect2.IsEmpty() )
4550 : : {
4551 : 0 : Rectangle aRect( Point( nX+rRect2.Left(),
4552 [ # # ][ # # ]: 0 : nY+rRect2.Top() ), rRect2.GetSize() );
4553 : :
4554 [ # # ]: 0 : DrawRect( aRect );
4555 : : }
4556 : 66998 : }
4557 : :
4558 : : // -----------------------------------------------------------------------
4559 : :
4560 : 14460 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
4561 : : {
4562 : 14460 : Color aOldLineColor = GetLineColor();
4563 : 14460 : Color aOldFillColor = GetFillColor();
4564 : 14460 : sal_Bool bOldMap = mbMap;
4565 : 14460 : GDIMetaFile* pOldMetaFile = mpMetaFile;
4566 : 14460 : mpMetaFile = NULL;
4567 [ + - ]: 14460 : EnableMapMode( sal_False );
4568 : :
4569 [ + - ]: 14460 : FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
4570 [ + - ]: 14460 : PolyPolygon aPolyPoly;
4571 [ + - ]: 14460 : Rectangle aRect1;
4572 [ + - ]: 14460 : Rectangle aRect2;
4573 : : long nEmphasisYOff;
4574 : : long nEmphasisWidth;
4575 : : long nEmphasisHeight;
4576 : : sal_Bool bPolyLine;
4577 : :
4578 [ - + ]: 14460 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
4579 : 0 : nEmphasisHeight = mnEmphasisDescent;
4580 : : else
4581 : 14460 : nEmphasisHeight = mnEmphasisAscent;
4582 : :
4583 : : ImplGetEmphasisMark( aPolyPoly, bPolyLine,
4584 : : aRect1, aRect2,
4585 : : nEmphasisYOff, nEmphasisWidth,
4586 : : nEmphasisMark,
4587 [ + - ]: 14460 : nEmphasisHeight, mpFontEntry->mnOrientation );
4588 : :
4589 [ + + ]: 14460 : if ( bPolyLine )
4590 : : {
4591 [ + - ]: 4640 : SetLineColor( GetTextColor() );
4592 [ + - ]: 4640 : SetFillColor();
4593 : : }
4594 : : else
4595 : : {
4596 [ + - ]: 9820 : SetLineColor();
4597 [ + - ]: 9820 : SetFillColor( GetTextColor() );
4598 : : }
4599 : :
4600 : 14460 : Point aOffset = Point(0,0);
4601 : :
4602 [ - + ]: 14460 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
4603 : 0 : aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
4604 : : else
4605 : 14460 : aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
4606 : :
4607 : 14460 : long nEmphasisWidth2 = nEmphasisWidth / 2;
4608 : 14460 : long nEmphasisHeight2 = nEmphasisHeight / 2;
4609 : 14460 : aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
4610 : :
4611 : 14460 : Point aOutPoint;
4612 [ + - ]: 14460 : Rectangle aRectangle;
4613 : 84975 : for( int nStart = 0;;)
4614 : : {
4615 : : sal_GlyphId nGlyphIndex;
4616 [ + - ][ + + ]: 84975 : if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aOutPoint, nStart ) )
4617 : : break;
4618 : :
4619 [ + - ][ - + ]: 70515 : if( !mpGraphics->GetGlyphBoundRect( nGlyphIndex, aRectangle ) )
4620 : 0 : continue;
4621 : :
4622 [ + - ][ + + ]: 70515 : if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
4623 : : {
4624 : 66998 : Point aAdjPoint = aOffset;
4625 [ + - ]: 66998 : aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
4626 [ + + ]: 66998 : if ( mpFontEntry->mnOrientation )
4627 : 41978 : ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
4628 : 66998 : aOutPoint += aAdjPoint;
4629 : 66998 : aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
4630 : 66998 : ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
4631 : 66998 : aOutPoint.X(), aOutPoint.Y(),
4632 [ + - ]: 70515 : aPolyPoly, bPolyLine, aRect1, aRect2 );
4633 : : }
4634 : : }
4635 : :
4636 [ + - ]: 14460 : SetLineColor( aOldLineColor );
4637 [ + - ]: 14460 : SetFillColor( aOldFillColor );
4638 [ + - ]: 14460 : EnableMapMode( bOldMap );
4639 [ + - ]: 14460 : mpMetaFile = pOldMetaFile;
4640 : 14460 : }
4641 : :
4642 : : // -----------------------------------------------------------------------
4643 : :
4644 : 0 : bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
4645 : : {
4646 : 0 : int nX = rSalLayout.DrawBase().X();
4647 : 0 : int nY = rSalLayout.DrawBase().Y();
4648 : :
4649 [ # # ]: 0 : Rectangle aBoundRect;
4650 : 0 : rSalLayout.DrawBase() = Point( 0, 0 );
4651 : 0 : rSalLayout.DrawOffset() = Point( 0, 0 );
4652 [ # # ][ # # ]: 0 : if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
4653 : : {
4654 : : // guess vertical text extents if GetBoundRect failed
4655 [ # # ]: 0 : int nRight = rSalLayout.GetTextWidth();
4656 : 0 : int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
4657 : 0 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
4658 [ # # ]: 0 : aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
4659 : : }
4660 : :
4661 : : // cache virtual device for rotation
4662 [ # # ]: 0 : if ( !mpOutDevData )
4663 [ # # ]: 0 : ImplInitOutDevData();
4664 [ # # ]: 0 : if ( !mpOutDevData->mpRotateDev )
4665 [ # # ][ # # ]: 0 : mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
4666 : 0 : VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
4667 : :
4668 : : // size it accordingly
4669 [ # # ][ # # ]: 0 : if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
[ # # ]
4670 : 0 : return false;
4671 : :
4672 [ # # ]: 0 : Font aFont( GetFont() );
4673 [ # # ]: 0 : aFont.SetOrientation( 0 );
4674 [ # # ]: 0 : aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
4675 [ # # ]: 0 : pVDev->SetFont( aFont );
4676 [ # # ]: 0 : pVDev->SetTextColor( Color( COL_BLACK ) );
4677 [ # # ]: 0 : pVDev->SetTextFillColor();
4678 [ # # ]: 0 : pVDev->ImplNewFont();
4679 [ # # ]: 0 : pVDev->ImplInitFont();
4680 [ # # ]: 0 : pVDev->ImplInitTextColor();
4681 : :
4682 : : // draw text into upper left corner
4683 : 0 : rSalLayout.DrawBase() -= aBoundRect.TopLeft();
4684 [ # # ]: 0 : rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
4685 : :
4686 [ # # ][ # # ]: 0 : Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
4687 [ # # ][ # # ]: 0 : if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
[ # # ][ # # ]
[ # # # # ]
4688 : 0 : return false;
4689 : :
4690 : : // calculate rotation offset
4691 [ # # ]: 0 : Polygon aPoly( aBoundRect );
4692 [ # # ]: 0 : aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
4693 [ # # ]: 0 : Point aPoint = aPoly.GetBoundRect().TopLeft();
4694 : 0 : aPoint += Point( nX, nY );
4695 : :
4696 : : // mask output with text colored bitmap
4697 : 0 : GDIMetaFile* pOldMetaFile = mpMetaFile;
4698 : 0 : long nOldOffX = mnOutOffX;
4699 : 0 : long nOldOffY = mnOutOffY;
4700 : 0 : sal_Bool bOldMap = mbMap;
4701 : :
4702 : 0 : mnOutOffX = 0L;
4703 : 0 : mnOutOffY = 0L;
4704 : 0 : mpMetaFile = NULL;
4705 [ # # ]: 0 : EnableMapMode( sal_False );
4706 : :
4707 [ # # ]: 0 : DrawMask( aPoint, aBmp, GetTextColor() );
4708 : :
4709 [ # # ]: 0 : EnableMapMode( bOldMap );
4710 : 0 : mnOutOffX = nOldOffX;
4711 : 0 : mnOutOffY = nOldOffY;
4712 : 0 : mpMetaFile = pOldMetaFile;
4713 : :
4714 [ # # ][ # # ]: 0 : return true;
[ # # ]
4715 : : }
4716 : :
4717 : : // -----------------------------------------------------------------------
4718 : :
4719 : 150376 : void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, sal_Bool bTextLines )
4720 : : {
4721 [ - + ]: 150376 : if( mpFontEntry->mnOwnOrientation )
4722 [ # # ]: 0 : if( ImplDrawRotateText( rSalLayout ) )
4723 : 150376 : return;
4724 : :
4725 : 150376 : long nOldX = rSalLayout.DrawBase().X();
4726 [ # # ][ + - ]: 150376 : if( ! (mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) )
[ - + ]
4727 : : {
4728 [ + + ]: 150376 : if( ImplHasMirroredGraphics() )
4729 : : {
4730 [ + - ]: 386 : long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
4731 : 386 : long x = rSalLayout.DrawBase().X();
4732 : 386 : rSalLayout.DrawBase().X() = w - 1 - x;
4733 [ - + ]: 386 : if( !IsRTLEnabled() )
4734 : : {
4735 : 0 : OutputDevice *pOutDevRef = (OutputDevice *)this;
4736 : : // mirror this window back
4737 : 0 : long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
4738 : 0 : rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
4739 : : }
4740 : : }
4741 [ - + ]: 149990 : else if( IsRTLEnabled() )
4742 : : {
4743 : : //long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
4744 : : //long x = rSalLayout.DrawBase().X();
4745 : 0 : OutputDevice *pOutDevRef = (OutputDevice *)this;
4746 : : // mirror this window back
4747 : 0 : long devX = pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
4748 : 0 : rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
4749 : : }
4750 : :
4751 : 150376 : rSalLayout.DrawText( *mpGraphics );
4752 : : }
4753 : :
4754 : 150376 : rSalLayout.DrawBase().X() = nOldX;
4755 : :
4756 [ + + ]: 150376 : if( bTextLines )
4757 : : ImplDrawTextLines( rSalLayout,
4758 : : maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
4759 : 15446 : maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
4760 : :
4761 : : // emphasis marks
4762 [ + + ]: 150376 : if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
4763 : 14460 : ImplDrawEmphasisMarks( rSalLayout );
4764 : : }
4765 : :
4766 : : // -----------------------------------------------------------------------
4767 : :
4768 : 6178 : void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
4769 : : {
4770 : 6178 : Color aOldColor = GetTextColor();
4771 : 6178 : Color aOldTextLineColor = GetTextLineColor();
4772 : 6178 : Color aOldOverlineColor = GetOverlineColor();
4773 [ + - ]: 6178 : FontRelief eRelief = maFont.GetRelief();
4774 : :
4775 : 6178 : Point aOrigPos = rSalLayout.DrawBase();
4776 [ + + ]: 6178 : if ( eRelief != RELIEF_NONE )
4777 : : {
4778 : 5797 : Color aReliefColor( COL_LIGHTGRAY );
4779 : 5797 : Color aTextColor( aOldColor );
4780 : :
4781 : 5797 : Color aTextLineColor( aOldTextLineColor );
4782 : 5797 : Color aOverlineColor( aOldOverlineColor );
4783 : :
4784 : : // we don't have a automatic color, so black is always drawn on white
4785 [ + + ]: 5797 : if ( aTextColor.GetColor() == COL_BLACK )
4786 : 1788 : aTextColor = Color( COL_WHITE );
4787 [ + + ]: 5797 : if ( aTextLineColor.GetColor() == COL_BLACK )
4788 : 1390 : aTextLineColor = Color( COL_WHITE );
4789 [ + + ]: 5797 : if ( aOverlineColor.GetColor() == COL_BLACK )
4790 : 1390 : aOverlineColor = Color( COL_WHITE );
4791 : :
4792 : : // relief-color is black for white text, in all other cases
4793 : : // we set this to LightGray
4794 [ + + ]: 5797 : if ( aTextColor.GetColor() == COL_WHITE )
4795 : 1832 : aReliefColor = Color( COL_BLACK );
4796 [ + - ]: 5797 : SetTextLineColor( aReliefColor );
4797 [ + - ]: 5797 : SetOverlineColor( aReliefColor );
4798 [ + - ]: 5797 : SetTextColor( aReliefColor );
4799 [ + - ]: 5797 : ImplInitTextColor();
4800 : :
4801 : : // calculate offset - for high resolution printers the offset
4802 : : // should be greater so that the effect is visible
4803 : 5797 : long nOff = 1;
4804 : 5797 : nOff += mnDPIX/300;
4805 : :
4806 [ + + ]: 5797 : if ( eRelief == RELIEF_ENGRAVED )
4807 : 2746 : nOff = -nOff;
4808 : 5797 : rSalLayout.DrawOffset() += Point( nOff, nOff);
4809 [ + - ]: 5797 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4810 : 5797 : rSalLayout.DrawOffset() -= Point( nOff, nOff);
4811 : :
4812 [ + - ]: 5797 : SetTextLineColor( aTextLineColor );
4813 [ + - ]: 5797 : SetOverlineColor( aOverlineColor );
4814 [ + - ]: 5797 : SetTextColor( aTextColor );
4815 [ + - ]: 5797 : ImplInitTextColor();
4816 [ + - ]: 5797 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4817 : :
4818 [ + - ]: 5797 : SetTextLineColor( aOldTextLineColor );
4819 [ + - ]: 5797 : SetOverlineColor( aOldOverlineColor );
4820 : :
4821 [ + + ]: 5797 : if ( aTextColor != aOldColor )
4822 : : {
4823 [ + - ]: 1788 : SetTextColor( aOldColor );
4824 [ + - ]: 5797 : ImplInitTextColor();
4825 : : }
4826 : : }
4827 : : else
4828 : : {
4829 [ + - ][ + + ]: 381 : if ( maFont.IsShadow() )
4830 : : {
4831 : 317 : long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
4832 [ + - ][ + + ]: 317 : if ( maFont.IsOutline() )
4833 : 252 : nOff++;
4834 [ + - ]: 317 : SetTextLineColor();
4835 [ + - ]: 317 : SetOverlineColor();
4836 [ + + ][ + - ]: 564 : if ( (GetTextColor().GetColor() == COL_BLACK)
[ + - ]
4837 [ + - ]: 247 : || (GetTextColor().GetLuminance() < 8) )
4838 [ + - ]: 317 : SetTextColor( Color( COL_LIGHTGRAY ) );
4839 : : else
4840 [ # # ]: 0 : SetTextColor( Color( COL_BLACK ) );
4841 [ + - ]: 317 : ImplInitTextColor();
4842 : 317 : rSalLayout.DrawBase() += Point( nOff, nOff );
4843 [ + - ]: 317 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4844 : 317 : rSalLayout.DrawBase() -= Point( nOff, nOff );
4845 [ + - ]: 317 : SetTextColor( aOldColor );
4846 [ + - ]: 317 : SetTextLineColor( aOldTextLineColor );
4847 [ + - ]: 317 : SetOverlineColor( aOldOverlineColor );
4848 [ + - ]: 317 : ImplInitTextColor();
4849 : :
4850 [ + - ][ + + ]: 317 : if ( !maFont.IsOutline() )
4851 [ + - ]: 65 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4852 : : }
4853 : :
4854 [ + - ][ + + ]: 381 : if ( maFont.IsOutline() )
4855 : : {
4856 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
4857 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4858 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
4859 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4860 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
4861 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4862 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
4863 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4864 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
4865 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4866 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
4867 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4868 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
4869 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4870 : 316 : rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
4871 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4872 : 316 : rSalLayout.DrawBase() = aOrigPos;
4873 : :
4874 [ + - ]: 316 : SetTextColor( Color( COL_WHITE ) );
4875 [ + - ]: 316 : SetTextLineColor( Color( COL_WHITE ) );
4876 [ + - ]: 316 : SetOverlineColor( Color( COL_WHITE ) );
4877 [ + - ]: 316 : ImplInitTextColor();
4878 [ + - ]: 316 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4879 [ + - ]: 316 : SetTextColor( aOldColor );
4880 [ + - ]: 316 : SetTextLineColor( aOldTextLineColor );
4881 [ + - ]: 316 : SetOverlineColor( aOldOverlineColor );
4882 [ + - ]: 316 : ImplInitTextColor();
4883 : : }
4884 : : }
4885 : 6178 : }
4886 : :
4887 : : // -----------------------------------------------------------------------
4888 : :
4889 : 143055 : void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
4890 : : {
4891 [ + + ]: 143055 : if( mbInitClipRegion )
4892 : 8486 : ImplInitClipRegion();
4893 [ + + ]: 143055 : if( mbOutputClipped )
4894 : 143055 : return;
4895 [ + + ]: 141734 : if( mbInitTextColor )
4896 : 43737 : ImplInitTextColor();
4897 : :
4898 : 141734 : rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
4899 : :
4900 [ + + ]: 141734 : if( IsTextFillColor() )
4901 : 5844 : ImplDrawTextBackground( rSalLayout );
4902 : :
4903 [ + + ]: 141734 : if( mbTextSpecial )
4904 : 6178 : ImplDrawSpecialText( rSalLayout );
4905 : : else
4906 : 135556 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4907 : : }
4908 : :
4909 : : // -----------------------------------------------------------------------
4910 : :
4911 : 2634 : long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
4912 : : long nWidth, const XubString& rStr,
4913 : : sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
4914 : : {
4915 : : DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
4916 : :
4917 [ - + ]: 2634 : if ( nWidth <= 0 )
4918 : 0 : nWidth = 1;
4919 : :
4920 : 2634 : long nMaxLineWidth = 0;
4921 : 2634 : rLineInfo.Clear();
4922 [ + - ][ + + ]: 2634 : if ( rStr.Len() && (nWidth > 0) )
[ + + ]
4923 : : {
4924 [ + - ]: 2397 : ::rtl::OUString aText( rStr );
4925 : 2397 : uno::Reference < i18n::XBreakIterator > xBI;
4926 : : // get service provider
4927 [ + - ]: 2397 : uno::Reference< lang::XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
4928 : :
4929 : 2397 : uno::Reference< linguistic2::XHyphenator > xHyph;
4930 [ + - ]: 2397 : if( xSMgr.is() )
4931 : : {
4932 [ + - ][ + - ]: 2397 : uno::Reference< linguistic2::XLinguServiceManager> xLinguMgr(xSMgr->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.linguistic2.LinguServiceManager"))),uno::UNO_QUERY);
[ + - ][ + - ]
4933 [ + + ]: 2397 : if ( xLinguMgr.is() )
4934 : : {
4935 [ + - ][ + - ]: 2393 : xHyph = xLinguMgr->getHyphenator();
[ + - ]
4936 : 2397 : }
4937 : : }
4938 : :
4939 [ + - ][ + - ]: 2397 : i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
[ + - ]
4940 : 2397 : i18n::LineBreakUserOptions aUserOptions;
4941 : :
4942 : 2397 : xub_StrLen nPos = 0;
4943 : 2397 : xub_StrLen nLen = rStr.Len();
4944 [ + + ]: 4801 : while ( nPos < nLen )
4945 : : {
4946 : 2404 : xub_StrLen nBreakPos = nPos;
4947 : :
4948 [ + + ][ + - ]: 18828 : while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
[ + - ][ + + ]
4949 : 16424 : nBreakPos++;
4950 : :
4951 [ + - ]: 2404 : long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
4952 [ + + ][ + + ]: 2404 : if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
4953 : : {
4954 [ + - ]: 7 : if ( !xBI.is() )
4955 [ + - ][ + - ]: 7 : xBI = vcl::unohelper::CreateBreakIterator();
4956 : :
4957 [ + - ]: 7 : if ( xBI.is() )
4958 : : {
4959 [ + - ][ + - ]: 7 : const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILocale());
4960 [ + - ]: 7 : xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
4961 : : DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
4962 : : //aHyphOptions.hyphenIndex = nSoftBreak;
4963 [ + - ][ + - ]: 7 : i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
4964 : 7 : nBreakPos = (xub_StrLen)aLBR.breakIndex;
4965 [ + + ]: 7 : if ( nBreakPos <= nPos )
4966 : 3 : nBreakPos = nSoftBreak;
4967 [ - + ]: 7 : if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
4968 : : {
4969 : : // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
4970 : : // die Silbentrennung jagen...
4971 : : // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
4972 : : // nBreakPos ist der Wort-Anfang
4973 : : // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
4974 : : // auf mehr als Zwei Zeilen gebrochen wird...
4975 [ # # ]: 0 : if ( xHyph.is() )
4976 : : {
4977 : 0 : sal_Unicode cAlternateReplChar = 0;
4978 [ # # ][ # # ]: 0 : i18n::Boundary aBoundary = xBI->getWordBoundary( aText, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
4979 : : // sal_uInt16 nWordStart = nBreakPos;
4980 : : // sal_uInt16 nBreakPos_OLD = nBreakPos;
4981 : 0 : sal_uInt16 nWordStart = nPos;
4982 : 0 : sal_uInt16 nWordEnd = (sal_uInt16) aBoundary.endPos;
4983 : : DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
4984 : :
4985 : 0 : sal_uInt16 nWordLen = nWordEnd - nWordStart;
4986 [ # # ][ # # ]: 0 : if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
4987 : : {
4988 : : // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
4989 : : // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
4990 [ # # ][ # # ]: 0 : String aWord( aText, nWordStart, nWordLen );
[ # # ]
4991 : 0 : sal_uInt16 nMinTrail = static_cast<sal_uInt16>(nWordEnd-nSoftBreak+1); //+1: Vor dem angeknacksten Buchstaben
4992 : 0 : uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
4993 [ # # ]: 0 : if (xHyph.is())
4994 [ # # ][ # # ]: 0 : xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.Len() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
[ # # ][ # # ]
[ # # ][ # # ]
4995 [ # # ]: 0 : if (xHyphWord.is())
4996 : : {
4997 [ # # ][ # # ]: 0 : sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
4998 [ # # ][ # # ]: 0 : sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
4999 : :
5000 [ # # ][ # # ]: 0 : if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
5001 : : {
5002 [ # # ]: 0 : if ( !bAlternate )
5003 : : {
5004 : 0 : nBreakPos = nWordStart + _nWordLen;
5005 : : }
5006 : : else
5007 : : {
5008 [ # # ][ # # ]: 0 : String aAlt( xHyphWord->getHyphenatedWord() );
[ # # ]
5009 : :
5010 : : // Wir gehen von zwei Faellen aus, die nun
5011 : : // vorliegen koennen:
5012 : : // 1) packen wird zu pak-ken
5013 : : // 2) Schiffahrt wird zu Schiff-fahrt
5014 : : // In Fall 1 muss ein Zeichen ersetzt werden,
5015 : : // in Fall 2 wird ein Zeichen hinzugefuegt.
5016 : : // Die Identifikation wird erschwert durch Worte wie
5017 : : // "Schiffahrtsbrennesseln", da der Hyphenator alle
5018 : : // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
5019 : : // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
5020 : : // Index des AlternativWord auf aWord schliessen.
5021 : :
5022 : : // Das ganze geraffel wird durch eine Funktion am
5023 : : // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
5024 : 0 : sal_uInt16 nAltStart = _nWordLen - 1;
5025 : 0 : sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
5026 : 0 : sal_uInt16 nTxtEnd = nTxtStart;
5027 : 0 : sal_uInt16 nAltEnd = nAltStart;
5028 : :
5029 : : // Die Bereiche zwischen den nStart und nEnd ist
5030 : : // die Differenz zwischen Alternativ- und OriginalString.
5031 [ # # ]: 0 : while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
[ # # # # ]
[ # # ]
5032 : 0 : aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
5033 : : {
5034 : 0 : ++nTxtEnd;
5035 : 0 : ++nAltEnd;
5036 : : }
5037 : :
5038 : : // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
5039 [ # # ]: 0 : if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
[ # # # # ]
[ # # ]
5040 : 0 : aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
5041 : : {
5042 : 0 : ++nAltEnd;
5043 : 0 : ++nTxtStart;
5044 : 0 : ++nTxtEnd;
5045 : : }
5046 : :
5047 : : DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" );
5048 : :
5049 [ # # ]: 0 : if ( nTxtEnd > nTxtStart )
5050 : 0 : cAlternateReplChar = aAlt.GetChar( nAltStart );
5051 : :
5052 : 0 : nBreakPos = nWordStart + nTxtStart;
5053 [ # # ]: 0 : if ( cAlternateReplChar )
5054 [ # # ]: 0 : nBreakPos++;
5055 : : }
5056 : : } // if (xHyphWord.is())
5057 [ # # ]: 0 : } // if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
5058 : : } // if ( xHyph.is() )
5059 : : } // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
5060 : : }
5061 [ + - ][ + - ]: 7 : nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
5062 : : }
5063 : : else
5064 : : {
5065 : : // fallback to something really simple
5066 : 0 : sal_uInt16 nSpacePos = STRING_LEN;
5067 : 0 : long nW = 0;
5068 [ # # ]: 0 : do
5069 : : {
5070 [ # # ]: 0 : nSpacePos = rStr.SearchBackward( sal_Unicode(' '), nSpacePos );
5071 [ # # ]: 0 : if( nSpacePos != STRING_NOTFOUND )
5072 : : {
5073 [ # # ]: 0 : if( nSpacePos > nPos )
5074 : 0 : nSpacePos--;
5075 [ # # ]: 0 : nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
5076 : : }
5077 : : } while( nW > nWidth );
5078 : :
5079 [ # # ]: 0 : if( nSpacePos != STRING_NOTFOUND )
5080 : : {
5081 : 0 : nBreakPos = nSpacePos;
5082 [ # # ]: 0 : nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
5083 [ # # ]: 0 : if( nBreakPos < rStr.Len()-1 )
5084 : 0 : nBreakPos++;
5085 : : }
5086 : : }
5087 : : }
5088 : :
5089 [ + + ]: 2404 : if ( nLineWidth > nMaxLineWidth )
5090 : 2397 : nMaxLineWidth = nLineWidth;
5091 : :
5092 [ + - ][ + - ]: 2404 : rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
5093 : :
5094 [ - + ]: 2404 : if ( nBreakPos == nPos )
5095 : 0 : nBreakPos++;
5096 : 2404 : nPos = nBreakPos;
5097 : :
5098 [ + - ][ - + ]: 2404 : if ( ( rStr.GetChar( nPos ) == _CR ) || ( rStr.GetChar( nPos ) == _LF ) )
[ - + ]
5099 : : {
5100 : 0 : nPos++;
5101 : : // CR/LF?
5102 [ # # ][ # # ]: 0 : if ( ( nPos < nLen ) && ( rStr.GetChar( nPos ) == _LF ) && ( rStr.GetChar( nPos-1 ) == _CR ) )
[ # # ][ # # ]
5103 : 0 : nPos++;
5104 : : }
5105 [ + - ]: 2397 : }
5106 : : }
5107 : : #ifdef DBG_UTIL
5108 : : for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
5109 : : {
5110 : : ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
5111 : : String aLine( rStr, pLine->GetIndex(), pLine->GetLen() );
5112 : : DBG_ASSERT( aLine.Search( _CR ) == STRING_NOTFOUND, "ImplGetTextLines - Found CR!" );
5113 : : DBG_ASSERT( aLine.Search( _LF ) == STRING_NOTFOUND, "ImplGetTextLines - Found LF!" );
5114 : : }
5115 : : #endif
5116 : :
5117 : 2634 : return nMaxLineWidth;
5118 : : }
5119 : :
5120 : : // =======================================================================
5121 : :
5122 : 147565 : void OutputDevice::SetAntialiasing( sal_uInt16 nMode )
5123 : : {
5124 [ + + ]: 147565 : if ( mnAntialiasing != nMode )
5125 : : {
5126 : 8481 : mnAntialiasing = nMode;
5127 : 8481 : mbInitFont = sal_True;
5128 : :
5129 [ + + ]: 8481 : if(mpGraphics)
5130 : : {
5131 : 1128 : mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
5132 : : }
5133 : : }
5134 : :
5135 [ - + ]: 147565 : if( mpAlphaVDev )
5136 : 0 : mpAlphaVDev->SetAntialiasing( nMode );
5137 : 147565 : }
5138 : :
5139 : : // -----------------------------------------------------------------------
5140 : :
5141 : 1148200 : void OutputDevice::SetFont( const Font& rNewFont )
5142 : : {
5143 : : OSL_TRACE( "OutputDevice::SetFont()" );
5144 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5145 : : DBG_CHKOBJ( &rNewFont, Font, NULL );
5146 : :
5147 [ + - ]: 1148200 : Font aFont( rNewFont );
5148 [ + - ][ + - ]: 1148200 : aFont.SetLanguage(rNewFont.GetLanguage());
5149 [ - + ]: 1148200 : if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
5150 : : DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
5151 : : DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
5152 : : {
5153 [ # # ]: 0 : Color aTextColor( aFont.GetColor() );
5154 : :
5155 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5156 : 0 : aTextColor = Color( COL_BLACK );
5157 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5158 : 0 : aTextColor = Color( COL_WHITE );
5159 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5160 : : {
5161 [ # # ]: 0 : const sal_uInt8 cLum = aTextColor.GetLuminance();
5162 : 0 : aTextColor = Color( cLum, cLum, cLum );
5163 : : }
5164 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5165 : 0 : aTextColor = GetSettings().GetStyleSettings().GetFontColor();
5166 : :
5167 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
5168 : : {
5169 : 0 : aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
5170 : 0 : (aTextColor.GetGreen() >> 1 ) | 0x80,
5171 : 0 : (aTextColor.GetBlue() >> 1 ) | 0x80 );
5172 : : }
5173 : :
5174 [ # # ]: 0 : aFont.SetColor( aTextColor );
5175 : :
5176 [ # # ]: 0 : sal_Bool bTransFill = aFont.IsTransparent();
5177 [ # # ]: 0 : if ( !bTransFill )
5178 : : {
5179 [ # # ]: 0 : Color aTextFillColor( aFont.GetFillColor() );
5180 : :
5181 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_BLACKFILL )
5182 : 0 : aTextFillColor = Color( COL_BLACK );
5183 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_WHITEFILL )
5184 : 0 : aTextFillColor = Color( COL_WHITE );
5185 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_GRAYFILL )
5186 : : {
5187 [ # # ]: 0 : const sal_uInt8 cLum = aTextFillColor.GetLuminance();
5188 : 0 : aTextFillColor = Color( cLum, cLum, cLum );
5189 : : }
5190 [ # # ]: 0 : else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
5191 : 0 : aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
5192 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_NOFILL )
5193 : : {
5194 : 0 : aTextFillColor = Color( COL_TRANSPARENT );
5195 : 0 : bTransFill = sal_True;
5196 : : }
5197 : :
5198 [ # # ][ # # ]: 0 : if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
5199 : : {
5200 : 0 : aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
5201 : 0 : (aTextFillColor.GetGreen() >> 1) | 0x80,
5202 : 0 : (aTextFillColor.GetBlue() >> 1) | 0x80 );
5203 : : }
5204 : :
5205 [ # # ]: 0 : aFont.SetFillColor( aTextFillColor );
5206 : : }
5207 : : }
5208 : :
5209 [ + + ]: 1148200 : if ( mpMetaFile )
5210 : : {
5211 [ + - ][ + - ]: 81313 : mpMetaFile->AddAction( new MetaFontAction( aFont ) );
[ + - ]
5212 : : // the color and alignment actions don't belong here
5213 : : // TODO: get rid of them without breaking anything...
5214 [ + - ][ + - ]: 81313 : mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
[ + - ][ + - ]
5215 [ + - ][ + - ]: 81313 : mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
[ + - ][ + - ]
[ + - ]
5216 : : }
5217 : :
5218 [ + - ][ + + ]: 1148200 : if ( !maFont.IsSameInstance( aFont ) )
5219 : : {
5220 : : // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
5221 : : // because SetTextColor() is used for this.
5222 : : // #i28759# maTextColor might have been changed behind our back, commit then, too.
5223 [ + - ][ + + : 1305581 : if( aFont.GetColor() != COL_TRANSPARENT
+ + - + ]
[ + - ]
[ + + # # ]
5224 [ + - ][ + - ]: 242464 : && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
[ + - ]
5225 : : {
5226 [ + - ]: 67968 : maTextColor = aFont.GetColor();
5227 : 67968 : mbInitTextColor = sal_True;
5228 [ + + ]: 67968 : if( mpMetaFile )
5229 [ + - ][ + - ]: 825 : mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
[ + - ][ + - ]
5230 : : }
5231 [ + - ]: 1063117 : maFont = aFont;
5232 : 1063117 : mbNewFont = sal_True;
5233 : :
5234 [ + + ]: 1063117 : if( mpAlphaVDev )
5235 : : {
5236 : : // #i30463#
5237 : : // Since SetFont might change the text color, apply that only
5238 : : // selectively to alpha vdev (which normally paints opaque text
5239 : : // with COL_BLACK)
5240 [ + - ][ + + ]: 22373 : if( aFont.GetColor() != COL_TRANSPARENT )
5241 : : {
5242 [ + - ]: 169 : mpAlphaVDev->SetTextColor( COL_BLACK );
5243 [ + - ]: 169 : aFont.SetColor( COL_TRANSPARENT );
5244 : : }
5245 : :
5246 [ + - ]: 22373 : mpAlphaVDev->SetFont( aFont );
5247 : : }
5248 [ + - ]: 1148200 : }
5249 : 1148200 : }
5250 : :
5251 : : // -----------------------------------------------------------------------
5252 : :
5253 : 937850 : void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode )
5254 : : {
5255 : : OSL_TRACE( "OutputDevice::SetTextLayoutMode()" );
5256 : :
5257 [ + + ]: 937850 : if( mpMetaFile )
5258 [ + - ]: 25195 : mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
5259 : :
5260 : 937850 : mnTextLayoutMode = nTextLayoutMode;
5261 : :
5262 [ + + ]: 937850 : if( mpAlphaVDev )
5263 : 43892 : mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
5264 : 937850 : }
5265 : :
5266 : : // -----------------------------------------------------------------------
5267 : :
5268 : 1372721 : void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
5269 : : {
5270 : : OSL_TRACE( "OutputDevice::SetTextLanguage()" );
5271 : :
5272 [ + + ]: 1372721 : if( mpMetaFile )
5273 [ + - ]: 31876 : mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
5274 : :
5275 : 1372721 : meTextLanguage = eTextLanguage;
5276 : :
5277 [ + + ]: 1372721 : if( mpAlphaVDev )
5278 : 43092 : mpAlphaVDev->SetDigitLanguage( eTextLanguage );
5279 : 1372721 : }
5280 : :
5281 : : // -----------------------------------------------------------------------
5282 : :
5283 : 568703 : void OutputDevice::SetTextColor( const Color& rColor )
5284 : : {
5285 : : OSL_TRACE( "OutputDevice::SetTextColor()" );
5286 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5287 : :
5288 : 568703 : Color aColor( rColor );
5289 : :
5290 [ - + ]: 568703 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5291 : : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5292 : : DRAWMODE_SETTINGSTEXT ) )
5293 : : {
5294 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5295 : 0 : aColor = Color( COL_BLACK );
5296 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5297 : 0 : aColor = Color( COL_WHITE );
5298 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5299 : : {
5300 [ # # ]: 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5301 : 0 : aColor = Color( cLum, cLum, cLum );
5302 : : }
5303 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5304 : 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
5305 : :
5306 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
5307 : : {
5308 : 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5309 : 0 : (aColor.GetGreen() >> 1) | 0x80,
5310 : 0 : (aColor.GetBlue() >> 1) | 0x80 );
5311 : : }
5312 : : }
5313 : :
5314 [ + + ]: 568703 : if ( mpMetaFile )
5315 [ + - ][ + - ]: 84191 : mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
[ + - ]
5316 : :
5317 [ + + ]: 568703 : if ( maTextColor != aColor )
5318 : : {
5319 : 26170 : maTextColor = aColor;
5320 : 26170 : mbInitTextColor = sal_True;
5321 : : }
5322 : :
5323 [ + + ]: 568703 : if( mpAlphaVDev )
5324 [ + - ]: 30645 : mpAlphaVDev->SetTextColor( COL_BLACK );
5325 : 568703 : }
5326 : :
5327 : : // -----------------------------------------------------------------------
5328 : :
5329 : 197572 : void OutputDevice::SetTextFillColor()
5330 : : {
5331 : : OSL_TRACE( "OutputDevice::SetTextFillColor()" );
5332 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5333 : :
5334 [ + + ]: 197572 : if ( mpMetaFile )
5335 [ + - ][ + - ]: 11017 : mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), sal_False ) );
[ + - ]
5336 : :
5337 [ + - ][ + + ]: 197572 : if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
5338 [ + - ]: 2226 : maFont.SetFillColor( Color( COL_TRANSPARENT ) );
5339 [ + + ]: 197572 : if ( !maFont.IsTransparent() )
5340 : 34 : maFont.SetTransparent( sal_True );
5341 : :
5342 [ + + ]: 197572 : if( mpAlphaVDev )
5343 : 32850 : mpAlphaVDev->SetTextFillColor();
5344 : 197572 : }
5345 : :
5346 : : // -----------------------------------------------------------------------
5347 : :
5348 : 22021 : void OutputDevice::SetTextFillColor( const Color& rColor )
5349 : : {
5350 : : OSL_TRACE( "OutputDevice::SetTextFillColor()" );
5351 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5352 : :
5353 : 22021 : Color aColor( rColor );
5354 [ + + ]: 22021 : sal_Bool bTransFill = ImplIsColorTransparent( aColor ) ? sal_True : sal_False;
5355 : :
5356 [ + + ]: 22021 : if ( !bTransFill )
5357 : : {
5358 [ - + ]: 19057 : if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
5359 : : DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
5360 : : DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
5361 : : {
5362 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_BLACKFILL )
5363 : 0 : aColor = Color( COL_BLACK );
5364 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_WHITEFILL )
5365 : 0 : aColor = Color( COL_WHITE );
5366 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_GRAYFILL )
5367 : : {
5368 [ # # ]: 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5369 : 0 : aColor = Color( cLum, cLum, cLum );
5370 : : }
5371 [ # # ]: 0 : else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
5372 : 0 : aColor = GetSettings().GetStyleSettings().GetWindowColor();
5373 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_NOFILL )
5374 : : {
5375 : 0 : aColor = Color( COL_TRANSPARENT );
5376 : 0 : bTransFill = sal_True;
5377 : : }
5378 : :
5379 [ # # ][ # # ]: 0 : if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
5380 : : {
5381 : 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5382 : 0 : (aColor.GetGreen() >> 1) | 0x80,
5383 : 0 : (aColor.GetBlue() >> 1) | 0x80 );
5384 : : }
5385 : : }
5386 : : }
5387 : :
5388 [ + + ]: 22021 : if ( mpMetaFile )
5389 [ + - ][ + - ]: 2662 : mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, sal_True ) );
[ + - ]
5390 : :
5391 [ + - ][ + + ]: 22021 : if ( maFont.GetFillColor() != aColor )
5392 [ + - ]: 12969 : maFont.SetFillColor( aColor );
5393 [ + - ][ + + ]: 22021 : if ( maFont.IsTransparent() != bTransFill )
5394 [ + - ]: 12836 : maFont.SetTransparent( bTransFill );
5395 : :
5396 [ + + ]: 22021 : if( mpAlphaVDev )
5397 [ + - ]: 2820 : mpAlphaVDev->SetTextFillColor( COL_BLACK );
5398 : 22021 : }
5399 : :
5400 : : // -----------------------------------------------------------------------
5401 : :
5402 : 9581 : Color OutputDevice::GetTextFillColor() const
5403 : : {
5404 [ + + ]: 9581 : if ( maFont.IsTransparent() )
5405 : 2844 : return Color( COL_TRANSPARENT );
5406 : : else
5407 : 9581 : return maFont.GetFillColor();
5408 : : }
5409 : :
5410 : : // -----------------------------------------------------------------------
5411 : :
5412 : 129636 : void OutputDevice::SetTextLineColor()
5413 : : {
5414 : : OSL_TRACE( "OutputDevice::SetTextLineColor()" );
5415 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5416 : :
5417 [ + + ]: 129636 : if ( mpMetaFile )
5418 [ + - ][ + - ]: 10762 : mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), sal_False ) );
[ + - ]
5419 : :
5420 : 129636 : maTextLineColor = Color( COL_TRANSPARENT );
5421 : :
5422 [ + + ]: 129636 : if( mpAlphaVDev )
5423 : 21568 : mpAlphaVDev->SetTextLineColor();
5424 : 129636 : }
5425 : :
5426 : : // -----------------------------------------------------------------------
5427 : :
5428 : 30149 : void OutputDevice::SetTextLineColor( const Color& rColor )
5429 : : {
5430 : : OSL_TRACE( "OutputDevice::SetTextLineColor()" );
5431 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5432 : :
5433 : 30149 : Color aColor( rColor );
5434 : :
5435 [ - + ]: 30149 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5436 : : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5437 : : DRAWMODE_SETTINGSTEXT ) )
5438 : : {
5439 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5440 : 0 : aColor = Color( COL_BLACK );
5441 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5442 : 0 : aColor = Color( COL_WHITE );
5443 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5444 : : {
5445 [ # # ]: 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5446 : 0 : aColor = Color( cLum, cLum, cLum );
5447 : : }
5448 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5449 : 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
5450 : :
5451 [ # # # # ]: 0 : if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
[ # # ]
5452 : 0 : && (aColor.GetColor() != COL_TRANSPARENT) )
5453 : : {
5454 : 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5455 : 0 : (aColor.GetGreen() >> 1) | 0x80,
5456 : 0 : (aColor.GetBlue() >> 1) | 0x80 );
5457 : : }
5458 : : }
5459 : :
5460 [ - + ]: 30149 : if ( mpMetaFile )
5461 [ # # ][ # # ]: 0 : mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, sal_True ) );
[ # # ]
5462 : :
5463 : 30149 : maTextLineColor = aColor;
5464 : :
5465 [ + + ]: 30149 : if( mpAlphaVDev )
5466 [ + - ]: 3336 : mpAlphaVDev->SetTextLineColor( COL_BLACK );
5467 : 30149 : }
5468 : :
5469 : : // -----------------------------------------------------------------------
5470 : :
5471 : 128980 : void OutputDevice::SetOverlineColor()
5472 : : {
5473 : : OSL_TRACE( "OutputDevice::SetOverlineColor()" );
5474 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5475 : :
5476 [ + + ]: 128980 : if ( mpMetaFile )
5477 [ + - ][ + - ]: 10762 : mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), sal_False ) );
[ + - ]
5478 : :
5479 : 128980 : maOverlineColor = Color( COL_TRANSPARENT );
5480 : :
5481 [ + + ]: 128980 : if( mpAlphaVDev )
5482 : 21568 : mpAlphaVDev->SetOverlineColor();
5483 : 128980 : }
5484 : :
5485 : : // -----------------------------------------------------------------------
5486 : :
5487 : 28806 : void OutputDevice::SetOverlineColor( const Color& rColor )
5488 : : {
5489 : : OSL_TRACE( "OutputDevice::SetOverlineColor()" );
5490 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5491 : :
5492 : 28806 : Color aColor( rColor );
5493 : :
5494 [ - + ]: 28806 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5495 : : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5496 : : DRAWMODE_SETTINGSTEXT ) )
5497 : : {
5498 [ # # ]: 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5499 : 0 : aColor = Color( COL_BLACK );
5500 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5501 : 0 : aColor = Color( COL_WHITE );
5502 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5503 : : {
5504 [ # # ]: 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5505 : 0 : aColor = Color( cLum, cLum, cLum );
5506 : : }
5507 [ # # ]: 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5508 : 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
5509 : :
5510 [ # # # # ]: 0 : if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
[ # # ]
5511 : 0 : && (aColor.GetColor() != COL_TRANSPARENT) )
5512 : : {
5513 : 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5514 : 0 : (aColor.GetGreen() >> 1) | 0x80,
5515 : 0 : (aColor.GetBlue() >> 1) | 0x80 );
5516 : : }
5517 : : }
5518 : :
5519 [ - + ]: 28806 : if ( mpMetaFile )
5520 [ # # ][ # # ]: 0 : mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, sal_True ) );
[ # # ]
5521 : :
5522 : 28806 : maOverlineColor = aColor;
5523 : :
5524 [ + + ]: 28806 : if( mpAlphaVDev )
5525 [ + - ]: 3336 : mpAlphaVDev->SetOverlineColor( COL_BLACK );
5526 : 28806 : }
5527 : :
5528 : : // -----------------------------------------------------------------------
5529 : :
5530 : :
5531 : 145042 : void OutputDevice::SetTextAlign( TextAlign eAlign )
5532 : : {
5533 : : OSL_TRACE( "OutputDevice::SetTextAlign()" );
5534 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5535 : :
5536 [ + + ]: 145042 : if ( mpMetaFile )
5537 [ + - ]: 10762 : mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
5538 : :
5539 [ + + ]: 145042 : if ( maFont.GetAlign() != eAlign )
5540 : : {
5541 : 7736 : maFont.SetAlign( eAlign );
5542 : 7736 : mbNewFont = sal_True;
5543 : : }
5544 : :
5545 [ + + ]: 145042 : if( mpAlphaVDev )
5546 : 32753 : mpAlphaVDev->SetTextAlign( eAlign );
5547 : 145042 : }
5548 : :
5549 : : // -----------------------------------------------------------------------
5550 : :
5551 : 0 : void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
5552 : : FontStrikeout eStrikeout,
5553 : : FontUnderline eUnderline,
5554 : : FontUnderline eOverline,
5555 : : sal_Bool bUnderlineAbove )
5556 : : {
5557 : : OSL_TRACE( "OutputDevice::DrawTextLine()" );
5558 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5559 : :
5560 [ # # ]: 0 : if ( mpMetaFile )
5561 [ # # ][ # # ]: 0 : mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
[ # # ]
5562 : :
5563 [ # # ][ # # ]: 0 : if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
[ # # ][ # # ]
[ # # ][ # # ]
5564 : : ((eOverline == UNDERLINE_NONE) || (eOverline == UNDERLINE_DONTKNOW)) &&
5565 : : ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
5566 : : return;
5567 : :
5568 [ # # ][ # # ]: 0 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
[ # # ][ # # ]
5569 : : return;
5570 : :
5571 : : // we need a graphics
5572 [ # # ][ # # ]: 0 : if( !mpGraphics && !ImplGetGraphics() )
[ # # ][ # # ]
5573 : : return;
5574 [ # # ]: 0 : if( mbInitClipRegion )
5575 [ # # ]: 0 : ImplInitClipRegion();
5576 [ # # ]: 0 : if( mbOutputClipped )
5577 : : return;
5578 : :
5579 : : // initialize font if needed to get text offsets
5580 : : // TODO: only needed for mnTextOff!=(0,0)
5581 [ # # ]: 0 : if( mbNewFont )
5582 [ # # ][ # # ]: 0 : if( !ImplNewFont() )
5583 : : return;
5584 [ # # ]: 0 : if( mbInitFont )
5585 [ # # ]: 0 : ImplInitFont();
5586 : :
5587 [ # # ]: 0 : Point aPos = ImplLogicToDevicePixel( rPos );
5588 [ # # ]: 0 : nWidth = ImplLogicWidthToDevicePixel( nWidth );
5589 : 0 : aPos += Point( mnTextOffX, mnTextOffY );
5590 [ # # ]: 0 : ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
5591 : :
5592 [ # # ]: 0 : if( mpAlphaVDev )
5593 [ # # ]: 0 : mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
5594 : : }
5595 : :
5596 : : // ------------------------------------------------------------------------
5597 : :
5598 : 3980 : void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
5599 : : sal_uInt16 nStyle )
5600 : : {
5601 : : OSL_TRACE( "OutputDevice::DrawWaveLine()" );
5602 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5603 : :
5604 [ + - ][ + - ]: 3980 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
[ - + ][ + - ]
5605 : : return;
5606 : :
5607 : : // we need a graphics
5608 [ - + ]: 3980 : if( !mpGraphics )
5609 [ # # ][ # # ]: 0 : if( !ImplGetGraphics() )
5610 : : return;
5611 : :
5612 [ + + ]: 3980 : if ( mbInitClipRegion )
5613 [ + - ]: 446 : ImplInitClipRegion();
5614 [ + - ]: 3980 : if ( mbOutputClipped )
5615 : : return;
5616 : :
5617 [ - + ]: 3980 : if( mbNewFont )
5618 [ # # ][ # # ]: 0 : if( !ImplNewFont() )
5619 : : return;
5620 : :
5621 [ + - ]: 3980 : Point aStartPt = ImplLogicToDevicePixel( rStartPos );
5622 [ + - ]: 3980 : Point aEndPt = ImplLogicToDevicePixel( rEndPos );
5623 : 3980 : long nStartX = aStartPt.X();
5624 : 3980 : long nStartY = aStartPt.Y();
5625 : 3980 : long nEndX = aEndPt.X();
5626 : 3980 : long nEndY = aEndPt.Y();
5627 : 3980 : short nOrientation = 0;
5628 : :
5629 : : // when rotated
5630 [ - + ][ + + ]: 3980 : if ( (nStartY != nEndY) || (nStartX > nEndX) )
5631 : : {
5632 : 340 : long nDX = nEndX - nStartX;
5633 [ - + ]: 340 : double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
5634 : 340 : nO /= F_PI1800;
5635 : 340 : nOrientation = (short)nO;
5636 : 340 : ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
5637 : : }
5638 : :
5639 : : long nWaveHeight;
5640 [ + + ]: 3980 : if ( nStyle == WAVE_NORMAL )
5641 : : {
5642 : 3876 : nWaveHeight = 3;
5643 : 3876 : nStartY++;
5644 : 3876 : nEndY++;
5645 : : }
5646 [ + + ]: 104 : else if( nStyle == WAVE_SMALL )
5647 : : {
5648 : 100 : nWaveHeight = 2;
5649 : 100 : nStartY++;
5650 : 100 : nEndY++;
5651 : : }
5652 : : else // WAVE_FLAT
5653 : 4 : nWaveHeight = 1;
5654 : :
5655 : : // #109280# make sure the waveline does not exceed the descent to avoid paint problems
5656 : 3980 : ImplFontEntry* pFontEntry = mpFontEntry;
5657 [ - + ]: 3980 : if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
5658 : 0 : nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
5659 : :
5660 : : ImplDrawWaveLine( nStartX, nStartY, 0, 0,
5661 : : nEndX-nStartX, nWaveHeight, 1,
5662 [ + - ]: 3980 : nOrientation, GetLineColor() );
5663 [ - + ]: 3980 : if( mpAlphaVDev )
5664 [ # # ]: 3980 : mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nStyle );
5665 : : }
5666 : :
5667 : : // -----------------------------------------------------------------------
5668 : :
5669 : 117327 : void OutputDevice::DrawText( const Point& rStartPt, const String& rStr,
5670 : : xub_StrLen nIndex, xub_StrLen nLen,
5671 : : MetricVector* pVector, String* pDisplayText
5672 : : )
5673 : : {
5674 [ + + ][ + + ]: 117327 : if( mpOutDevData && mpOutDevData->mpRecordLayout )
5675 : : {
5676 : 2424 : pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
5677 : 2424 : pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
5678 : : }
5679 : :
5680 : : OSL_TRACE( "OutputDevice::DrawText()" );
5681 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5682 : :
5683 : : #if OSL_DEBUG_LEVEL > 2
5684 : : fprintf( stderr, " OutputDevice::DrawText(\"%s\")\n",
5685 : : OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
5686 : : #endif
5687 : :
5688 [ + + ]: 117327 : if ( mpMetaFile )
5689 [ + - ][ + - ]: 2577 : mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
[ + - ]
5690 [ + + ]: 117327 : if( pVector )
5691 : : {
5692 [ + - ]: 2476 : Region aClip( GetClipRegion() );
5693 [ + - ]: 2476 : if( meOutDevType == OUTDEV_WINDOW )
5694 [ + - ][ + - ]: 2476 : aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
[ + - ]
5695 [ + + ][ + - ]: 2476 : if( mpOutDevData && mpOutDevData->mpRecordLayout )
5696 : : {
5697 [ + - ]: 2424 : mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.Len() );
5698 [ + - ]: 2424 : aClip.Intersect( mpOutDevData->maRecordRect );
5699 : : }
5700 [ + - ][ + - ]: 2476 : if( ! aClip.IsNull() )
5701 : : {
5702 [ + - ]: 2476 : MetricVector aTmp;
5703 [ + - ]: 2476 : GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
5704 : :
5705 : 2476 : bool bInserted = false;
5706 [ + - ][ + - ]: 11444 : for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
[ + - ][ + + ]
5707 : : {
5708 : 8968 : bool bAppend = false;
5709 : :
5710 [ + - ][ + - ]: 8968 : if( aClip.IsOver( *it ) )
[ + + ]
5711 : 1846 : bAppend = true;
5712 [ + + ][ + + ]: 7122 : else if( rStr.GetChar( nIndex ) == ' ' && bInserted )
[ + + ]
5713 : : {
5714 : 222 : MetricVector::const_iterator next = it;
5715 [ + - ]: 222 : ++next;
5716 [ + - ][ + - ]: 222 : if( next != aTmp.end() && aClip.IsOver( *next ) )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - # # ]
5717 : 222 : bAppend = true;
5718 : : }
5719 : :
5720 [ + + ]: 8968 : if( bAppend )
5721 : : {
5722 [ + - ][ + - ]: 2068 : pVector->push_back( *it );
5723 [ + - ]: 2068 : if( pDisplayText )
5724 [ + - ]: 2068 : pDisplayText->Append( rStr.GetChar( nIndex ) );
5725 : 2068 : bInserted = true;
5726 : : }
5727 : 2476 : }
5728 : : }
5729 : : else
5730 : : {
5731 [ # # ]: 0 : GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
5732 [ # # ]: 0 : if( pDisplayText )
5733 [ # # ][ # # ]: 0 : pDisplayText->Append( rStr.Copy( nIndex, nLen ) );
[ # # ]
5734 [ + - ]: 2476 : }
5735 : : }
5736 : :
5737 [ + + ][ + + ]: 117327 : if ( !IsDeviceOutputNecessary() || pVector )
[ + + ]
5738 : 117327 : return;
5739 : :
5740 : 114849 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, NULL, true );
5741 [ + + ]: 114849 : if( pSalLayout )
5742 : : {
5743 : 95396 : ImplDrawText( *pSalLayout );
5744 : 95396 : pSalLayout->Release();
5745 : : }
5746 : :
5747 [ + + ]: 114849 : if( mpAlphaVDev )
5748 : 3488 : mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
5749 : : }
5750 : :
5751 : : // -----------------------------------------------------------------------
5752 : :
5753 : 588038 : long OutputDevice::GetTextWidth( const String& rStr,
5754 : : xub_StrLen nIndex, xub_StrLen nLen ) const
5755 : : {
5756 : : OSL_TRACE( "OutputDevice::GetTextWidth()" );
5757 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5758 : :
5759 : 588038 : long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
5760 : 588038 : return nWidth;
5761 : : }
5762 : :
5763 : : // -----------------------------------------------------------------------
5764 : :
5765 : 711362 : long OutputDevice::GetTextHeight() const
5766 : : {
5767 : : OSL_TRACE( "OutputDevice::GetTextHeight()" );
5768 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5769 : :
5770 [ + + ]: 711362 : if( mbNewFont )
5771 [ - + ]: 411452 : if( !ImplNewFont() )
5772 : 0 : return 0;
5773 [ + + ]: 711362 : if( mbInitFont )
5774 [ - + ]: 367515 : if( !ImplNewFont() )
5775 : 0 : return 0;
5776 : :
5777 : 711362 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
5778 : :
5779 [ + + ]: 711362 : if ( mbMap )
5780 : 517845 : nHeight = ImplDevicePixelToLogicHeight( nHeight );
5781 : :
5782 : 711362 : return nHeight;
5783 : : }
5784 : :
5785 : : // -----------------------------------------------------------------------
5786 : :
5787 : 49891 : void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
5788 : : const sal_Int32* pDXAry,
5789 : : xub_StrLen nIndex, xub_StrLen nLen )
5790 : : {
5791 : : OSL_TRACE( "OutputDevice::DrawTextArray()" );
5792 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5793 : :
5794 [ + + ]: 49891 : if ( mpMetaFile )
5795 [ + - ][ + - ]: 4466 : mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
[ + - ]
5796 : :
5797 [ + + ]: 49891 : if ( !IsDeviceOutputNecessary() )
5798 : 4089 : return;
5799 [ - + ][ # # ]: 45802 : if( !mpGraphics && !ImplGetGraphics() )
[ - + ]
5800 : 0 : return;
5801 [ + + ]: 45802 : if( mbInitClipRegion )
5802 : 6687 : ImplInitClipRegion();
5803 [ + + ]: 45802 : if( mbOutputClipped )
5804 : 397 : return;
5805 : :
5806 : 45405 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
5807 [ + + ]: 45405 : if( pSalLayout )
5808 : : {
5809 : 44514 : ImplDrawText( *pSalLayout );
5810 : 44514 : pSalLayout->Release();
5811 : : }
5812 : :
5813 [ + + ]: 45405 : if( mpAlphaVDev )
5814 : 49891 : mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
5815 : : }
5816 : :
5817 : : // -----------------------------------------------------------------------
5818 : :
5819 : 859066 : long OutputDevice::GetTextArray( const String& rStr, sal_Int32* pDXAry,
5820 : : xub_StrLen nIndex, xub_StrLen nLen ) const
5821 : : {
5822 : : OSL_TRACE( "OutputDevice::GetTextArray()" );
5823 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5824 : :
5825 [ + + ]: 859066 : if( nIndex >= rStr.Len() )
5826 : 235179 : return 0;
5827 [ + + ]: 623887 : if( (sal_uLong)nIndex+nLen >= rStr.Len() )
5828 : 539486 : nLen = rStr.Len() - nIndex;
5829 : :
5830 : : // do layout
5831 [ + - ]: 623887 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
5832 [ - + ]: 623887 : if( !pSalLayout )
5833 : 0 : return 0;
5834 : :
5835 : 623887 : long nWidth = pSalLayout->FillDXArray( pDXAry );
5836 : 623887 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
5837 : 623887 : pSalLayout->Release();
5838 : :
5839 : : // convert virtual char widths to virtual absolute positions
5840 [ + + ]: 623887 : if( pDXAry )
5841 [ + + ]: 4013620 : for( int i = 1; i < nLen; ++i )
5842 : 3746462 : pDXAry[ i ] += pDXAry[ i-1 ];
5843 : :
5844 : : // convert from font units to logical units
5845 [ + + ]: 623887 : if( mbMap )
5846 : : {
5847 [ + + ]: 358778 : if( pDXAry )
5848 [ + + ]: 4279884 : for( int i = 0; i < nLen; ++i )
5849 : 4013152 : pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
5850 : 358778 : nWidth = ImplDevicePixelToLogicWidth( nWidth );
5851 : : }
5852 : :
5853 [ - + ]: 623887 : if( nWidthFactor > 1 )
5854 : : {
5855 [ # # ]: 0 : if( pDXAry )
5856 [ # # ]: 0 : for( int i = 0; i < nLen; ++i )
5857 : 0 : pDXAry[i] /= nWidthFactor;
5858 : 0 : nWidth /= nWidthFactor;
5859 : : }
5860 : :
5861 : 859066 : return nWidth;
5862 : : }
5863 : :
5864 : : // -----------------------------------------------------------------------
5865 : :
5866 : 19933 : bool OutputDevice::GetCaretPositions( const XubString& rStr, sal_Int32* pCaretXArray,
5867 : : xub_StrLen nIndex, xub_StrLen nLen,
5868 : : sal_Int32* pDXAry, long nLayoutWidth,
5869 : : sal_Bool bCellBreaking ) const
5870 : : {
5871 : : OSL_TRACE( "OutputDevice::GetCaretPositions()" );
5872 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5873 : :
5874 [ - + ]: 19933 : if( nIndex >= rStr.Len() )
5875 : 0 : return false;
5876 [ + - ]: 19933 : if( (sal_uLong)nIndex+nLen >= rStr.Len() )
5877 : 19933 : nLen = rStr.Len() - nIndex;
5878 : :
5879 : : // layout complex text
5880 : : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
5881 [ + - ]: 19933 : Point(0,0), nLayoutWidth, pDXAry );
5882 [ - + ]: 19933 : if( !pSalLayout )
5883 : 0 : return false;
5884 : :
5885 : 19933 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
5886 : 19933 : pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
5887 : 19933 : long nWidth = pSalLayout->GetTextWidth();
5888 : 19933 : pSalLayout->Release();
5889 : :
5890 : : // fixup unknown caret positions
5891 : : int i;
5892 [ + + ]: 20183 : for( i = 0; i < 2 * nLen; ++i )
5893 [ + + ]: 20167 : if( pCaretXArray[ i ] >= 0 )
5894 : 19917 : break;
5895 : 19933 : long nXPos = pCaretXArray[ i ];
5896 [ + + ]: 245781 : for( i = 0; i < 2 * nLen; ++i )
5897 : : {
5898 [ + + ]: 225848 : if( pCaretXArray[ i ] >= 0 )
5899 : 225598 : nXPos = pCaretXArray[ i ];
5900 : : else
5901 : 250 : pCaretXArray[ i ] = nXPos;
5902 : : }
5903 : :
5904 : : // handle window mirroring
5905 [ + + ]: 19933 : if( IsRTLEnabled() )
5906 : : {
5907 [ + + ]: 383 : for( i = 0; i < 2 * nLen; ++i )
5908 : 298 : pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
5909 : : }
5910 : :
5911 : : // convert from font units to logical units
5912 [ - + ]: 19933 : if( mbMap )
5913 : : {
5914 [ # # ]: 0 : for( i = 0; i < 2*nLen; ++i )
5915 : 0 : pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
5916 : : }
5917 : :
5918 [ - + ]: 19933 : if( nWidthFactor != 1 )
5919 : : {
5920 [ # # ]: 0 : for( i = 0; i < 2*nLen; ++i )
5921 : 0 : pCaretXArray[i] /= nWidthFactor;
5922 : : }
5923 : :
5924 : : // if requested move caret position to cell limits
5925 : : if( bCellBreaking )
5926 : : {
5927 : : ; // TODO
5928 : : }
5929 : :
5930 : 19933 : return true;
5931 : : }
5932 : :
5933 : : // -----------------------------------------------------------------------
5934 : :
5935 : 65257 : void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
5936 : : const String& rStr,
5937 : : xub_StrLen nIndex, xub_StrLen nLen )
5938 : : {
5939 : : OSL_TRACE( "OutputDevice::DrawStretchText()" );
5940 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5941 : :
5942 [ + + ]: 65257 : if ( mpMetaFile )
5943 [ + - ][ + - ]: 62112 : mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
[ + - ]
5944 : :
5945 [ + + ]: 65257 : if ( !IsDeviceOutputNecessary() )
5946 : 65257 : return;
5947 : :
5948 : 3145 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, nWidth, NULL, true );
5949 [ + - ]: 3145 : if( pSalLayout )
5950 : : {
5951 : 3145 : ImplDrawText( *pSalLayout );
5952 : 3145 : pSalLayout->Release();
5953 : : }
5954 : :
5955 [ - + ]: 3145 : if( mpAlphaVDev )
5956 : 0 : mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
5957 : : }
5958 : :
5959 : : // -----------------------------------------------------------------------
5960 : :
5961 : 981170 : ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( String& rStr,
5962 : : xub_StrLen nMinIndex, xub_StrLen nLen,
5963 : : long nPixelWidth, const sal_Int32* pDXArray ) const
5964 : : {
5965 : : // get string length for calculating extents
5966 : 981170 : xub_StrLen nEndIndex = rStr.Len();
5967 [ + + ]: 981170 : if( (sal_uLong)nMinIndex + nLen < nEndIndex )
5968 : 152416 : nEndIndex = nMinIndex + nLen;
5969 : :
5970 : : // don't bother if there is nothing to do
5971 [ - + ]: 981170 : if( nEndIndex < nMinIndex )
5972 : 0 : nEndIndex = nMinIndex;
5973 : :
5974 : 981170 : int nLayoutFlags = 0;
5975 [ + + ]: 981170 : if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
5976 : 3562 : nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
5977 [ + + ]: 981170 : if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
5978 : 386400 : nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
5979 [ + + ]: 594770 : else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
5980 : : {
5981 : : // disable Bidi if no RTL hint and no RTL codes used
5982 : 591208 : const xub_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
5983 : 591208 : const xub_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
5984 [ + + ]: 3706870 : for( ; pStr < pEnd; ++pStr )
5985 [ + + ][ + - ]: 3115662 : if( ((*pStr >= 0x0580) && (*pStr < 0x0800)) // middle eastern scripts
[ + + ][ + - ]
[ + + ][ - + ]
5986 : : || ((*pStr >= 0xFB18) && (*pStr < 0xFE00)) // hebrew + arabic A presentation forms
5987 : : || ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
5988 : 0 : break;
5989 [ + - ]: 591208 : if( pStr >= pEnd )
5990 : 591208 : nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
5991 : : }
5992 : :
5993 [ + + ]: 981170 : if( mbKerning )
5994 : 195118 : nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
5995 [ - + ]: 981170 : if( maFont.GetKerning() & KERNING_ASIAN )
5996 : 0 : nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
5997 [ - + ]: 981170 : if( maFont.IsVertical() )
5998 : 0 : nLayoutFlags |= SAL_LAYOUT_VERTICAL;
5999 : :
6000 [ - + ]: 981170 : if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
6001 : 0 : nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
6002 [ + + ]: 981170 : else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
6003 : 212770 : nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
6004 : : else
6005 : : {
6006 : : // disable CTL for non-CTL text
6007 : 768400 : const sal_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
6008 : 768400 : const sal_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
6009 [ + + ]: 22011003 : for( ; pStr < pEnd; ++pStr )
6010 [ + + ][ + + ]: 21244004 : if( ((*pStr >= 0x0300) && (*pStr < 0x0370)) // diacritical marks
[ + + ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
[ + + ][ - + ]
6011 : : || ((*pStr >= 0x0590) && (*pStr < 0x10A0)) // many CTL scripts
6012 : : || ((*pStr >= 0x1100) && (*pStr < 0x1200)) // hangul jamo
6013 : : || ((*pStr >= 0x1700) && (*pStr < 0x1900)) // many CTL scripts
6014 : : || ((*pStr >= 0xFB1D) && (*pStr < 0xFE00)) // middle east presentation
6015 : : || ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation B
6016 : 1401 : break;
6017 [ + + ]: 768400 : if( pStr >= pEnd )
6018 : 766999 : nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
6019 : : }
6020 : :
6021 [ + + ]: 981170 : if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
6022 : : {
6023 : : // disable character localization when no digits used
6024 : 488393 : const sal_Unicode* pBase = rStr.GetBuffer();
6025 : 488393 : const sal_Unicode* pStr = pBase + nMinIndex;
6026 : 488393 : const sal_Unicode* pEnd = pBase + nEndIndex;
6027 [ + + ]: 19975118 : for( ; pStr < pEnd; ++pStr )
6028 : : {
6029 : : // TODO: are there non-digit localizations?
6030 [ + + ][ + + ]: 19486725 : if( (*pStr >= '0') && (*pStr <= '9') )
6031 : : {
6032 : : // translate characters to local preference
6033 : 10657779 : sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
6034 [ - + ]: 10657779 : if( cChar != *pStr )
6035 : : // TODO: are the localized digit surrogates?
6036 : : rStr.SetChar( static_cast<sal_uInt16>(pStr - pBase),
6037 : 0 : static_cast<sal_Unicode>(cChar) );
6038 : : }
6039 : : }
6040 : : }
6041 : :
6042 : : // right align for RTL text, DRAWPOS_REVERSED, RTL window style
6043 : 981170 : bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
6044 [ + + ]: 981170 : if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
6045 : 34413 : bRightAlign = false;
6046 [ - + ]: 946757 : else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
6047 : 0 : bRightAlign = true;
6048 : : // SSA: hack for western office, ie text get right aligned
6049 : : // for debugging purposes of mirrored UI
6050 : : //static const char* pEnv = getenv( "SAL_RTL_MIRRORTEXT" );
6051 : 981170 : bool bRTLWindow = IsRTLEnabled();
6052 : 981170 : bRightAlign ^= bRTLWindow;
6053 [ + + ]: 981170 : if( bRightAlign )
6054 : 939 : nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
6055 : :
6056 : : // set layout options
6057 : 981170 : ImplLayoutArgs aLayoutArgs( rStr.GetBuffer(), rStr.Len(), nMinIndex, nEndIndex, nLayoutFlags );
6058 : :
6059 [ + - ]: 981170 : int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
6060 : 981170 : aLayoutArgs.SetOrientation( nOrientation );
6061 : :
6062 : 981170 : aLayoutArgs.SetLayoutWidth( nPixelWidth );
6063 : 981170 : aLayoutArgs.SetDXArray( pDXArray );
6064 : :
6065 : 981170 : return aLayoutArgs;
6066 : : }
6067 : :
6068 : : // -----------------------------------------------------------------------
6069 : :
6070 : 1001409 : SalLayout* OutputDevice::ImplLayout( const String& rOrigStr,
6071 : : xub_StrLen nMinIndex,
6072 : : xub_StrLen nLen,
6073 : : const Point& rLogicalPos,
6074 : : long nLogicalWidth,
6075 : : const sal_Int32* pDXArray,
6076 : : bool bFilter ) const
6077 : : {
6078 : : // we need a graphics
6079 [ + + ]: 1001409 : if( !mpGraphics )
6080 [ + - ][ - + ]: 421 : if( !ImplGetGraphics() )
6081 : 0 : return NULL;
6082 : :
6083 : : // initialize font if needed
6084 [ + + ]: 1001409 : if( mbNewFont )
6085 [ + - ][ - + ]: 138244 : if( !ImplNewFont() )
6086 : 0 : return NULL;
6087 [ + + ]: 1001409 : if( mbInitFont )
6088 [ + - ]: 176248 : ImplInitFont();
6089 : :
6090 : : // check string index and length
6091 [ + + ]: 1001409 : if( (unsigned)nMinIndex + nLen > rOrigStr.Len() )
6092 : : {
6093 : 184172 : const int nNewLen = (int)rOrigStr.Len() - nMinIndex;
6094 [ + + ]: 184172 : if( nNewLen <= 0 )
6095 : 13171 : return NULL;
6096 : 171001 : nLen = static_cast<xub_StrLen>(nNewLen);
6097 : : }
6098 : :
6099 [ + - ]: 988238 : String aStr = rOrigStr;
6100 : :
6101 : : // filter out special markers
6102 [ + + ]: 988238 : if( bFilter )
6103 : : {
6104 : 150228 : xub_StrLen nCutStart, nCutStop, nOrgLen = nLen;
6105 [ + - ]: 150228 : rtl::OUString aTmpStr(aStr);
6106 [ + - ][ + - ]: 150228 : bool bFiltered = mpGraphics->filterText( rOrigStr, aTmpStr, nMinIndex, nLen, nCutStart, nCutStop );
6107 [ + - ]: 150228 : aStr = aTmpStr;
6108 [ + + ]: 150228 : if( !nLen )
6109 : 7173 : return NULL;
6110 : :
6111 [ - + ][ # # ]: 143055 : if( bFiltered && nCutStop != nCutStart && pDXArray )
[ # # ]
6112 : : {
6113 [ # # ]: 0 : if( !nLen )
6114 : 0 : pDXArray = NULL;
6115 : : else
6116 : : {
6117 : 0 : sal_Int32* pAry = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
6118 [ # # ]: 0 : if( nCutStart > nMinIndex )
6119 : 0 : memcpy( pAry, pDXArray, sizeof(sal_Int32)*(nCutStart-nMinIndex) );
6120 : : // note: nCutStart will never be smaller than nMinIndex
6121 : 0 : memcpy( pAry+nCutStart-nMinIndex,
6122 : 0 : pDXArray + nOrgLen - (nCutStop-nMinIndex),
6123 : 0 : sizeof(sal_Int32)*(nLen - (nCutStart-nMinIndex)) );
6124 : 143055 : pDXArray = pAry;
6125 : : }
6126 [ + + ]: 150228 : }
6127 : : }
6128 : :
6129 : : // convert from logical units to physical units
6130 : : // recode string if needed
6131 [ - + ]: 981065 : if( mpFontEntry->mpConversion )
6132 [ # # ]: 0 : mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.Len() );
6133 : :
6134 : 981065 : long nPixelWidth = nLogicalWidth;
6135 [ + + ][ + - ]: 981065 : if( nLogicalWidth && mbMap )
6136 [ + - ]: 3041 : nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
6137 [ + + ][ + + ]: 981065 : if( pDXArray && mbMap )
6138 : : {
6139 : : // convert from logical units to font units using a temporary array
6140 : 36817 : sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
6141 : : // using base position for better rounding a.k.a. "dancing characters"
6142 [ + - ]: 36817 : int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
6143 [ + + ]: 1529759 : for( int i = 0; i < nLen; ++i )
6144 [ + - ]: 1492942 : pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
6145 : :
6146 : 36817 : pDXArray = pTempDXAry;
6147 : : }
6148 : :
6149 [ + - ]: 981065 : ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
6150 : :
6151 : : // get matching layout object for base font
6152 : 981065 : SalLayout* pSalLayout = NULL;
6153 [ - + ]: 981065 : if( mpPDFWriter )
6154 [ # # ]: 0 : pSalLayout = mpPDFWriter->GetTextLayout( aLayoutArgs, &mpFontEntry->maFontSelData );
6155 : :
6156 [ + - ]: 981065 : if( !pSalLayout )
6157 [ + - ]: 981065 : pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
6158 : :
6159 : : // layout text
6160 [ + - ][ + - ]: 981065 : if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
[ - + ][ - + ]
6161 : : {
6162 [ # # ]: 0 : pSalLayout->Release();
6163 : 0 : pSalLayout = NULL;
6164 : : }
6165 : :
6166 [ - + ]: 981065 : if( !pSalLayout )
6167 : 0 : return NULL;
6168 : :
6169 : : // do glyph fallback if needed
6170 : : // #105768# avoid fallback for very small font sizes
6171 [ + + ]: 981065 : if( aLayoutArgs.NeedFallback() )
6172 [ + - ][ + - ]: 9357 : if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) )
6173 [ + - ]: 9357 : pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs );
6174 : :
6175 : : // position, justify, etc. the layout
6176 [ + - ]: 981065 : pSalLayout->AdjustLayout( aLayoutArgs );
6177 [ + - ]: 981065 : pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
6178 : : // adjust to right alignment if necessary
6179 [ + + ]: 981065 : if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
6180 : : {
6181 : : long nRTLOffset;
6182 [ + + ]: 939 : if( pDXArray )
6183 : 14 : nRTLOffset = pDXArray[ nLen - 1 ];
6184 [ - + ]: 925 : else if( nPixelWidth )
6185 : 0 : nRTLOffset = nPixelWidth;
6186 : : else
6187 [ + - ]: 925 : nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
6188 : 939 : pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
6189 : : }
6190 : :
6191 [ + - ]: 1001409 : return pSalLayout;
6192 : : }
6193 : :
6194 : 9357 : SalLayout* OutputDevice::getFallbackFontThatFits(ImplFontEntry &rFallbackFont,
6195 : : FontSelectPattern &rFontSelData, int nFallbackLevel,
6196 : : ImplLayoutArgs& rLayoutArgs, const ImplFontMetricData& rOrigMetric) const
6197 : : {
6198 [ + - ]: 9357 : rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
6199 : :
6200 : 9357 : rLayoutArgs.ResetPos();
6201 [ + - ]: 9357 : SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
6202 : :
6203 [ - + ]: 9357 : if (!pFallback)
6204 : 0 : return NULL;
6205 : :
6206 [ + - ][ - + ]: 9357 : if (!pFallback->LayoutText(rLayoutArgs))
6207 : : {
6208 : : // there is no need for a font that couldn't resolve anything
6209 [ # # ]: 0 : pFallback->Release();
6210 : 0 : return NULL;
6211 : : }
6212 : :
6213 [ + - ]: 9357 : Rectangle aBoundRect;
6214 : 9357 : bool bHaveBounding = false;
6215 [ + - ]: 9357 : Rectangle aRectangle;
6216 : :
6217 [ + - ]: 9357 : pFallback->AdjustLayout( rLayoutArgs );
6218 : :
6219 : : //All we care about here is getting the vertical bounds of this text and
6220 : : //make sure it will fit inside the available space
6221 : 9357 : Point aPos;
6222 : 19011 : for( int nStart = 0;;)
6223 : : {
6224 : : sal_GlyphId nLGlyph;
6225 [ + - ][ + + ]: 19011 : if( !pFallback->GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
6226 : : break;
6227 : :
6228 : 9654 : sal_GlyphId nFontTag = nFallbackLevel << GF_FONTSHIFT;
6229 : 9654 : nLGlyph |= nFontTag;
6230 : :
6231 : : // get bounding rectangle of individual glyph
6232 [ + - ][ + - ]: 9654 : if( mpGraphics->GetGlyphBoundRect( nLGlyph, aRectangle ) )
6233 : : {
6234 : : // merge rectangle
6235 [ + - ]: 9654 : aRectangle += aPos;
6236 [ + - ]: 9654 : aBoundRect.Union( aRectangle );
6237 : 9654 : bHaveBounding = true;
6238 : : }
6239 : : }
6240 : :
6241 : : //Shrink it down if it won't fit
6242 [ + - ]: 9357 : if (bHaveBounding)
6243 : : {
6244 : 9357 : long nGlyphsAscent = -aBoundRect.Top();
6245 : : float fScaleTop = nGlyphsAscent > rOrigMetric.mnAscent ?
6246 [ + + ]: 9357 : rOrigMetric.mnAscent/(float)nGlyphsAscent : 1;
6247 : 9357 : long nGlyphsDescent = aBoundRect.Bottom();
6248 : : float fScaleBottom = nGlyphsDescent > rOrigMetric.mnDescent ?
6249 [ + + ]: 9357 : rOrigMetric.mnDescent/(float)nGlyphsDescent : 1;
6250 [ + + ]: 9357 : float fScale = fScaleBottom < fScaleTop ? fScaleBottom : fScaleTop;
6251 [ + + ]: 9357 : if (fScale < 1)
6252 : : {
6253 : 3393 : long nOrigHeight = rFontSelData.mnHeight;
6254 : 3393 : long nNewHeight = static_cast<int>(static_cast<float>(rFontSelData.mnHeight) * fScale);
6255 : :
6256 [ - + ]: 3393 : if (nNewHeight == nOrigHeight)
6257 : 0 : --nNewHeight;
6258 : :
6259 [ + - ]: 3393 : pFallback->Release();
6260 : :
6261 : 3393 : rFontSelData.mnHeight = nNewHeight;
6262 [ + - ]: 3393 : rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
6263 : 3393 : rFontSelData.mnHeight = nOrigHeight;
6264 : :
6265 : 3393 : rLayoutArgs.ResetPos();
6266 [ + - ]: 3393 : pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
6267 [ + - ][ + - ]: 3393 : if (pFallback && !pFallback->LayoutText(rLayoutArgs))
[ - + ][ - + ]
6268 : : {
6269 [ # # ]: 0 : pFallback->Release();
6270 : 0 : pFallback = NULL;
6271 : : }
6272 : : SAL_WARN_IF(pFallback, "vcl.gdi", "we couldn't layout text with a smaller point size that worked with a bigger one");
6273 : : }
6274 : : }
6275 : 9357 : return pFallback;
6276 : : }
6277 : :
6278 : : // -----------------------------------------------------------------------
6279 : :
6280 : 9357 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
6281 : : {
6282 : : // prepare multi level glyph fallback
6283 : 9357 : MultiSalLayout* pMultiSalLayout = NULL;
6284 [ + - ]: 9357 : ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
6285 [ + - ]: 9357 : rLayoutArgs.PrepareFallback();
6286 : 9357 : rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
6287 : :
6288 : : // get list of unicodes that need glyph fallback
6289 : 9357 : int nCharPos = -1;
6290 : 9357 : bool bRTL = false;
6291 : 9357 : rtl::OUStringBuffer aMissingCodeBuf;
6292 [ + - ][ + + ]: 19011 : while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
6293 [ + - ]: 9654 : aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
6294 : 9357 : rLayoutArgs.ResetPos();
6295 [ + - ]: 9357 : rtl::OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
6296 : :
6297 [ + - ]: 9357 : FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
6298 : :
6299 [ + - ]: 9357 : ImplFontMetricData aOrigMetric( aFontSelData );
6300 : : // TODO: use cached metric in fontentry
6301 [ + - ]: 9357 : mpGraphics->GetFontMetric( &aOrigMetric );
6302 : :
6303 : : // when device specific font substitution may have been performed for
6304 : : // the originally selected font then make sure that a fallback to that
6305 : : // font is performed first
6306 : 9357 : int nDevSpecificFallback = 0;
6307 [ + + ][ - + ]: 9357 : if( mpOutDevData && !mpOutDevData->maDevFontSubst.Empty() )
[ - + ]
6308 : 0 : nDevSpecificFallback = 1;
6309 : :
6310 : : // try if fallback fonts support the missing unicodes
6311 [ + - ]: 9357 : for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
6312 : : {
6313 : : // find a font family suited for glyph fallback
6314 : : #ifndef FONTFALLBACK_HOOKS_DISABLED
6315 : : // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
6316 : : // if the system-specific glyph fallback is active
6317 : 9357 : aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
6318 : : #endif
6319 : : ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontList,
6320 [ + - ]: 9357 : aFontSelData, nFallbackLevel-nDevSpecificFallback, aMissingCodes );
6321 [ - + ]: 9357 : if( !pFallbackFont )
6322 : 0 : break;
6323 : :
6324 : 9357 : aFontSelData.mpFontEntry = pFallbackFont;
6325 : 9357 : aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
6326 [ + - ][ + - ]: 9357 : if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
6327 : : {
6328 : : // ignore fallback font if it is the same as the original font
6329 [ - + ]: 9357 : if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
6330 : : {
6331 [ # # ]: 0 : mpFontCache->Release( pFallbackFont );
6332 : 0 : continue;
6333 : : }
6334 : : }
6335 : :
6336 : : // create and add glyph fallback layout to multilayout
6337 : : SalLayout* pFallback = getFallbackFontThatFits(*pFallbackFont, aFontSelData,
6338 [ + - ]: 9357 : nFallbackLevel, rLayoutArgs, aOrigMetric);
6339 [ + - ]: 9357 : if (pFallback)
6340 : : {
6341 [ + - ]: 9357 : if( !pMultiSalLayout )
6342 [ + - ][ + - ]: 9357 : pMultiSalLayout = new MultiSalLayout( *pSalLayout );
6343 : : pMultiSalLayout->AddFallback( *pFallback,
6344 [ + - ]: 9357 : rLayoutArgs.maRuns, aFontSelData.mpFontData );
6345 [ - + ]: 9357 : if (nFallbackLevel == MAX_FALLBACK-1)
6346 [ # # ]: 0 : pMultiSalLayout->SetInComplete();
6347 : : }
6348 : :
6349 [ + - ]: 9357 : mpFontCache->Release( pFallbackFont );
6350 : :
6351 : : // break when this fallback was sufficient
6352 [ + - ][ + - ]: 9357 : if( !rLayoutArgs.PrepareFallback() )
6353 : 9357 : break;
6354 : : }
6355 : :
6356 [ + - ][ + - ]: 9357 : if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
[ + - ][ + - ]
6357 : 9357 : pSalLayout = pMultiSalLayout;
6358 : :
6359 : : // restore orig font settings
6360 [ + - ]: 9357 : pSalLayout->InitFont();
6361 [ + - ]: 9357 : rLayoutArgs.maRuns = aLayoutRuns;
6362 : :
6363 [ + - ][ + - ]: 9357 : return pSalLayout;
6364 : : }
6365 : :
6366 : : // -----------------------------------------------------------------------
6367 : :
6368 : 0 : sal_Bool OutputDevice::GetTextIsRTL(
6369 : : const String& rString,
6370 : : xub_StrLen nIndex, xub_StrLen nLen ) const
6371 : : {
6372 [ # # ]: 0 : String aStr( rString );
6373 [ # # ]: 0 : ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
6374 : 0 : bool bRTL = false;
6375 : 0 : int nCharPos = -1;
6376 [ # # ]: 0 : aArgs.GetNextPos( &nCharPos, &bRTL );
6377 [ # # ][ # # ]: 0 : return (nCharPos != nIndex) ? sal_True : sal_False;
6378 : : }
6379 : :
6380 : : // -----------------------------------------------------------------------
6381 : :
6382 : 56357 : xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
6383 : : xub_StrLen nIndex, xub_StrLen nLen,
6384 : : long nCharExtra, sal_Bool /*TODO: bCellBreaking*/ ) const
6385 : : {
6386 : : OSL_TRACE( "OutputDevice::GetTextBreak()" );
6387 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6388 : :
6389 [ + - ]: 56357 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
6390 : 56357 : xub_StrLen nRetVal = STRING_LEN;
6391 [ + - ]: 56357 : if( pSalLayout )
6392 : : {
6393 : : // convert logical widths into layout units
6394 : : // NOTE: be very careful to avoid rounding errors for nCharExtra case
6395 : : // problem with rounding errors especially for small nCharExtras
6396 : : // TODO: remove when layout units have subpixel granularity
6397 : 56357 : long nWidthFactor = pSalLayout->GetUnitsPerPixel();
6398 [ + - ]: 56357 : long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
6399 : 56357 : nTextWidth *= nWidthFactor * nSubPixelFactor;
6400 : 56357 : long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
6401 : 56357 : long nExtraPixelWidth = 0;
6402 [ + + ]: 56357 : if( nCharExtra != 0 )
6403 : : {
6404 : 240 : nCharExtra *= nWidthFactor * nSubPixelFactor;
6405 : 240 : nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
6406 : : }
6407 : 56357 : nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6408 : :
6409 : 56357 : pSalLayout->Release();
6410 : : }
6411 : :
6412 : 56357 : return nRetVal;
6413 : : }
6414 : :
6415 : : // -----------------------------------------------------------------------
6416 : :
6417 : 0 : xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
6418 : : sal_Unicode nHyphenatorChar, xub_StrLen& rHyphenatorPos,
6419 : : xub_StrLen nIndex, xub_StrLen nLen,
6420 : : long nCharExtra ) const
6421 : : {
6422 : : OSL_TRACE( "OutputDevice::GetTextBreak()" );
6423 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6424 : :
6425 : 0 : rHyphenatorPos = STRING_LEN;
6426 : :
6427 [ # # ]: 0 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
6428 [ # # ]: 0 : if( !pSalLayout )
6429 : 0 : return STRING_LEN;
6430 : :
6431 : : // convert logical widths into layout units
6432 : : // NOTE: be very careful to avoid rounding errors for nCharExtra case
6433 : : // problem with rounding errors especially for small nCharExtras
6434 : : // TODO: remove when layout units have subpixel granularity
6435 : 0 : long nWidthFactor = pSalLayout->GetUnitsPerPixel();
6436 [ # # ]: 0 : long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
6437 : :
6438 : 0 : nTextWidth *= nWidthFactor * nSubPixelFactor;
6439 [ # # ]: 0 : long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
6440 : 0 : long nExtraPixelWidth = 0;
6441 [ # # ]: 0 : if( nCharExtra != 0 )
6442 : : {
6443 : 0 : nCharExtra *= nWidthFactor * nSubPixelFactor;
6444 [ # # ]: 0 : nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
6445 : : }
6446 : :
6447 : : // calculate un-hyphenated break position
6448 [ # # ]: 0 : xub_StrLen nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6449 : :
6450 : : // calculate hyphenated break position
6451 : 0 : rtl::OUString aHyphenatorStr(nHyphenatorChar);
6452 : 0 : xub_StrLen nTempLen = 1;
6453 [ # # ][ # # ]: 0 : SalLayout* pHyphenatorLayout = ImplLayout( aHyphenatorStr, 0, nTempLen );
[ # # ]
6454 [ # # ]: 0 : if( pHyphenatorLayout )
6455 : : {
6456 : : // calculate subpixel width of hyphenation character
6457 [ # # ]: 0 : long nHyphenatorPixelWidth = pHyphenatorLayout->GetTextWidth() * nSubPixelFactor;
6458 [ # # ]: 0 : pHyphenatorLayout->Release();
6459 : :
6460 : : // calculate hyphenated break position
6461 : 0 : nTextPixelWidth -= nHyphenatorPixelWidth;
6462 [ # # ]: 0 : if( nExtraPixelWidth > 0 )
6463 : 0 : nTextPixelWidth -= nExtraPixelWidth;
6464 : :
6465 [ # # ]: 0 : rHyphenatorPos = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6466 : :
6467 [ # # ]: 0 : if( rHyphenatorPos > nRetVal )
6468 : 0 : rHyphenatorPos = nRetVal;
6469 : : }
6470 : :
6471 [ # # ]: 0 : pSalLayout->Release();
6472 : 0 : return nRetVal;
6473 : : }
6474 : :
6475 : : // -----------------------------------------------------------------------
6476 : :
6477 : 8738 : void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
6478 : : const String& rOrigStr, sal_uInt16 nStyle,
6479 : : MetricVector* pVector, String* pDisplayText,
6480 : : ::vcl::ITextLayout& _rLayout )
6481 : : {
6482 : 8738 : Color aOldTextColor;
6483 : 8738 : Color aOldTextFillColor;
6484 : 8738 : sal_Bool bRestoreFillColor = false;
6485 [ + - ][ + + ]: 8738 : if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
6486 : : {
6487 : 1315 : sal_Bool bHighContrastBlack = sal_False;
6488 : 1315 : sal_Bool bHighContrastWhite = sal_False;
6489 : 1315 : const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
6490 [ - + ]: 1315 : if( rStyleSettings.GetHighContrastMode() )
6491 : : {
6492 : 0 : Color aCol;
6493 [ # # ]: 0 : if( rTargetDevice.IsBackground() )
6494 [ # # ]: 0 : aCol = rTargetDevice.GetBackground().GetColor();
6495 : : else
6496 : : // best guess is the face color here
6497 : : // but it may be totally wrong. the background color
6498 : : // was typically already reset
6499 : 0 : aCol = rStyleSettings.GetFaceColor();
6500 : :
6501 [ # # ]: 0 : bHighContrastBlack = aCol.IsDark();
6502 [ # # ]: 0 : bHighContrastWhite = aCol.IsBright();
6503 : : }
6504 : :
6505 : 1315 : aOldTextColor = rTargetDevice.GetTextColor();
6506 [ - + ][ + - ]: 1315 : if ( rTargetDevice.IsTextFillColor() )
6507 : : {
6508 : 0 : bRestoreFillColor = sal_True;
6509 [ # # ]: 0 : aOldTextFillColor = rTargetDevice.GetTextFillColor();
6510 : : }
6511 [ - + ]: 1315 : if( bHighContrastBlack )
6512 [ # # ]: 0 : rTargetDevice.SetTextColor( COL_GREEN );
6513 [ - + ]: 1315 : else if( bHighContrastWhite )
6514 [ # # ]: 0 : rTargetDevice.SetTextColor( COL_LIGHTGREEN );
6515 : : else
6516 : : {
6517 : : // draw disabled text always without shadow
6518 : : // as it fits better with native look
6519 : : /*
6520 : : SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
6521 : : Rectangle aRect = rRect;
6522 : : aRect.Move( 1, 1 );
6523 : : DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
6524 : : */
6525 [ + - ]: 1315 : rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
6526 : : }
6527 : : }
6528 : :
6529 [ + - ]: 8738 : long nWidth = rRect.GetWidth();
6530 [ + - ]: 8738 : long nHeight = rRect.GetHeight();
6531 : :
6532 [ + + ][ - + ]: 8738 : if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
[ + - ]
6533 : 8738 : return;
6534 : :
6535 : 8738 : Point aPos = rRect.TopLeft();
6536 : :
6537 [ + - ]: 8738 : long nTextHeight = rTargetDevice.GetTextHeight();
6538 [ + - ]: 8738 : TextAlign eAlign = rTargetDevice.GetTextAlign();
6539 : 8738 : xub_StrLen nMnemonicPos = STRING_NOTFOUND;
6540 : :
6541 [ + - ]: 8738 : String aStr = rOrigStr;
6542 [ + + ]: 8738 : if ( nStyle & TEXT_DRAW_MNEMONIC )
6543 [ + - ][ + - ]: 1753 : aStr = GetNonMnemonicString( aStr, nMnemonicPos );
[ + - ]
6544 : :
6545 [ + - ][ + + ]: 8738 : const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
6546 : :
6547 : : // Mehrzeiligen Text behandeln wir anders
6548 [ + + ]: 8738 : if ( nStyle & TEXT_DRAW_MULTILINE )
6549 : : {
6550 : :
6551 [ + - ]: 1771 : XubString aLastLine;
6552 [ + - ]: 1771 : ImplMultiTextLineInfo aMultiLineInfo;
6553 : : ImplTextLineInfo* pLineInfo;
6554 : : xub_StrLen i;
6555 : : xub_StrLen nLines;
6556 : : xub_StrLen nFormatLines;
6557 : :
6558 [ + - ]: 1771 : if ( nTextHeight )
6559 : : {
6560 [ + - ]: 1771 : long nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
6561 : 1771 : nLines = (xub_StrLen)(nHeight/nTextHeight);
6562 : 1771 : nFormatLines = aMultiLineInfo.Count();
6563 [ + + ]: 1771 : if ( !nLines )
6564 : 166 : nLines = 1;
6565 [ + + ]: 1771 : if ( nFormatLines > nLines )
6566 : : {
6567 [ + - ]: 3 : if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
6568 : : {
6569 : : // Letzte Zeile zusammenbauen und kuerzen
6570 : 3 : nFormatLines = nLines-1;
6571 : :
6572 : 3 : pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
6573 [ + - ][ + - ]: 3 : aLastLine = convertLineEnd(aStr.Copy(pLineInfo->GetIndex()), LINEEND_LF);
[ + - ][ + - ]
[ + - ]
6574 : : // Alle LineFeed's durch Spaces ersetzen
6575 : 3 : xub_StrLen nLastLineLen = aLastLine.Len();
6576 [ + + ]: 39 : for ( i = 0; i < nLastLineLen; i++ )
6577 : : {
6578 [ - + ]: 36 : if ( aLastLine.GetChar( i ) == _LF )
6579 [ # # ]: 0 : aLastLine.SetChar( i, ' ' );
6580 : : }
6581 [ + - ][ + - ]: 3 : aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
[ + - ]
6582 : 3 : nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
6583 : 3 : nStyle |= TEXT_DRAW_TOP;
6584 : : }
6585 : : }
6586 : : else
6587 : : {
6588 [ + + ]: 1768 : if ( nMaxTextWidth <= nWidth )
6589 : 1741 : nStyle &= ~TEXT_DRAW_CLIP;
6590 : : }
6591 : :
6592 : : // Muss in der Hoehe geclippt werden?
6593 [ + + ]: 1771 : if ( nFormatLines*nTextHeight > nHeight )
6594 : 163 : nStyle |= TEXT_DRAW_CLIP;
6595 : :
6596 : : // Clipping setzen
6597 [ + + ]: 1771 : if ( nStyle & TEXT_DRAW_CLIP )
6598 : : {
6599 [ + - ]: 163 : rTargetDevice.Push( PUSH_CLIPREGION );
6600 [ + - ]: 163 : rTargetDevice.IntersectClipRegion( rRect );
6601 : : }
6602 : :
6603 : : // Vertikales Alignment
6604 [ - + ]: 1771 : if ( nStyle & TEXT_DRAW_BOTTOM )
6605 : 0 : aPos.Y() += nHeight-(nFormatLines*nTextHeight);
6606 [ + + ]: 1771 : else if ( nStyle & TEXT_DRAW_VCENTER )
6607 : 1522 : aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
6608 : :
6609 : : // Font Alignment
6610 [ - + ]: 1771 : if ( eAlign == ALIGN_BOTTOM )
6611 : 0 : aPos.Y() += nTextHeight;
6612 [ - + ]: 1771 : else if ( eAlign == ALIGN_BASELINE )
6613 [ # # ][ # # ]: 0 : aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
[ # # ]
6614 : :
6615 : : // Alle Zeilen ausgeben, bis auf die letzte
6616 [ + + ]: 3541 : for ( i = 0; i < nFormatLines; i++ )
6617 : : {
6618 : 1770 : pLineInfo = aMultiLineInfo.GetLine( i );
6619 [ - + ]: 1770 : if ( nStyle & TEXT_DRAW_RIGHT )
6620 : 0 : aPos.X() += nWidth-pLineInfo->GetWidth();
6621 [ + + ]: 1770 : else if ( nStyle & TEXT_DRAW_CENTER )
6622 : 489 : aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
6623 : 1770 : xub_StrLen nIndex = pLineInfo->GetIndex();
6624 : 1770 : xub_StrLen nLineLen = pLineInfo->GetLen();
6625 [ + - ]: 1770 : _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
6626 [ + + ]: 1770 : if ( bDrawMnemonics )
6627 : : {
6628 [ + - ][ + + ]: 1768 : if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
6629 : : {
6630 : : long nMnemonicX;
6631 : : long nMnemonicY;
6632 : : long nMnemonicWidth;
6633 : :
6634 : 16 : sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
6635 : : /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
6636 [ + - ]: 16 : nIndex, nLineLen );
6637 : 16 : long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
6638 : 16 : long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
6639 [ + - ]: 16 : nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
6640 : :
6641 [ + - ]: 16 : Point aTempPos = rTargetDevice.LogicToPixel( aPos );
6642 [ + - ]: 16 : nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
6643 [ + - ][ + - ]: 16 : nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
[ + - ][ + - ]
6644 [ + - ]: 16 : rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6645 : : }
6646 : : }
6647 : 1770 : aPos.Y() += nTextHeight;
6648 : 1770 : aPos.X() = rRect.Left();
6649 : : }
6650 : :
6651 : :
6652 : : // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
6653 : : // da die Zeile gekuerzt wurde
6654 [ + + ]: 1771 : if ( aLastLine.Len() )
6655 [ + - ]: 3 : _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
6656 : :
6657 : : // Clipping zuruecksetzen
6658 [ + + ]: 1771 : if ( nStyle & TEXT_DRAW_CLIP )
6659 [ + - ]: 163 : rTargetDevice.Pop();
6660 [ + - ]: 1771 : }
6661 : : }
6662 : : else
6663 : : {
6664 [ + - ]: 6967 : long nTextWidth = _rLayout.GetTextWidth( aStr, 0, STRING_LEN );
6665 : :
6666 : : // Evt. Text kuerzen
6667 [ + + ]: 6967 : if ( nTextWidth > nWidth )
6668 : : {
6669 [ - + ]: 173 : if ( nStyle & TEXT_DRAW_ELLIPSIS )
6670 : : {
6671 [ # # ][ # # ]: 0 : aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
[ # # ]
6672 : 0 : nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
6673 : 0 : nStyle |= TEXT_DRAW_LEFT;
6674 [ # # ]: 0 : nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
6675 : : }
6676 : : }
6677 : : else
6678 : : {
6679 [ + - ]: 6794 : if ( nTextHeight <= nHeight )
6680 : 6794 : nStyle &= ~TEXT_DRAW_CLIP;
6681 : : }
6682 : :
6683 : : // horizontal text alignment
6684 [ + + ]: 6967 : if ( nStyle & TEXT_DRAW_RIGHT )
6685 : 677 : aPos.X() += nWidth-nTextWidth;
6686 [ + + ]: 6290 : else if ( nStyle & TEXT_DRAW_CENTER )
6687 : 100 : aPos.X() += (nWidth-nTextWidth)/2;
6688 : :
6689 : : // vertical font alignment
6690 [ - + ]: 6967 : if ( eAlign == ALIGN_BOTTOM )
6691 : 0 : aPos.Y() += nTextHeight;
6692 [ - + ]: 6967 : else if ( eAlign == ALIGN_BASELINE )
6693 [ # # ][ # # ]: 0 : aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
[ # # ]
6694 : :
6695 [ - + ]: 6967 : if ( nStyle & TEXT_DRAW_BOTTOM )
6696 : 0 : aPos.Y() += nHeight-nTextHeight;
6697 [ + + ]: 6967 : else if ( nStyle & TEXT_DRAW_VCENTER )
6698 : 3246 : aPos.Y() += (nHeight-nTextHeight)/2;
6699 : :
6700 : 6967 : long nMnemonicX = 0;
6701 : 6967 : long nMnemonicY = 0;
6702 : 6967 : long nMnemonicWidth = 0;
6703 [ - + ]: 6967 : if ( nMnemonicPos != STRING_NOTFOUND )
6704 : : {
6705 : 0 : sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
6706 [ # # ]: 0 : /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
6707 : 0 : long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
6708 : 0 : long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
6709 [ # # ]: 0 : nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
6710 : :
6711 [ # # ]: 0 : Point aTempPos = rTargetDevice.LogicToPixel( aPos );
6712 [ # # ]: 0 : nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
6713 [ # # ][ # # ]: 0 : nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
[ # # ][ # # ]
6714 : : }
6715 : :
6716 [ - + ]: 6967 : if ( nStyle & TEXT_DRAW_CLIP )
6717 : : {
6718 [ # # ]: 0 : rTargetDevice.Push( PUSH_CLIPREGION );
6719 [ # # ]: 0 : rTargetDevice.IntersectClipRegion( rRect );
6720 [ # # ]: 0 : _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
6721 [ # # ]: 0 : if ( bDrawMnemonics )
6722 : : {
6723 [ # # ]: 0 : if ( nMnemonicPos != STRING_NOTFOUND )
6724 [ # # ]: 0 : rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6725 : : }
6726 [ # # ]: 0 : rTargetDevice.Pop();
6727 : : }
6728 : : else
6729 : : {
6730 [ + - ]: 6967 : _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
6731 [ + - ]: 6967 : if ( bDrawMnemonics )
6732 : : {
6733 [ - + ]: 6967 : if ( nMnemonicPos != STRING_NOTFOUND )
6734 [ # # ]: 0 : rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6735 : : }
6736 : : }
6737 : : }
6738 : :
6739 [ + + ][ + - ]: 8738 : if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
6740 : : {
6741 [ + - ]: 1315 : rTargetDevice.SetTextColor( aOldTextColor );
6742 [ - + ]: 1315 : if ( bRestoreFillColor )
6743 [ # # ]: 0 : rTargetDevice.SetTextFillColor( aOldTextFillColor );
6744 [ + - ]: 8738 : }
6745 : : }
6746 : :
6747 : : // -----------------------------------------------------------------------
6748 : :
6749 : 0 : void OutputDevice::AddTextRectActions( const Rectangle& rRect,
6750 : : const String& rOrigStr,
6751 : : sal_uInt16 nStyle,
6752 : : GDIMetaFile& rMtf )
6753 : : {
6754 : : OSL_TRACE( "OutputDevice::AddTextRectActions( const Rectangle& )" );
6755 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6756 : :
6757 [ # # ][ # # ]: 0 : if ( !rOrigStr.Len() || rRect.IsEmpty() )
[ # # ][ # # ]
6758 : : return;
6759 : :
6760 : : // we need a graphics
6761 [ # # ][ # # ]: 0 : if( !mpGraphics && !ImplGetGraphics() )
[ # # ][ # # ]
6762 : : return;
6763 [ # # ]: 0 : if( mbInitClipRegion )
6764 [ # # ]: 0 : ImplInitClipRegion();
6765 : :
6766 : : // temporarily swap in passed mtf for action generation, and
6767 : : // disable output generation.
6768 : 0 : const sal_Bool bOutputEnabled( IsOutputEnabled() );
6769 : 0 : GDIMetaFile* pMtf = mpMetaFile;
6770 : :
6771 : 0 : mpMetaFile = &rMtf;
6772 [ # # ]: 0 : EnableOutput( sal_False );
6773 : :
6774 : : // #i47157# Factored out to ImplDrawTextRect(), to be shared
6775 : : // between us and DrawText()
6776 : 0 : DefaultTextLayout aLayout( *this );
6777 [ # # ]: 0 : ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
6778 : :
6779 : : // and restore again
6780 [ # # ]: 0 : EnableOutput( bOutputEnabled );
6781 [ # # ]: 0 : mpMetaFile = pMtf;
6782 : : }
6783 : :
6784 : : // -----------------------------------------------------------------------
6785 : :
6786 : 15279 : void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle,
6787 : : MetricVector* pVector, String* pDisplayText,
6788 : : ::vcl::ITextLayout* _pTextLayout )
6789 : : {
6790 [ - + ][ # # ]: 15279 : if( mpOutDevData && mpOutDevData->mpRecordLayout )
6791 : : {
6792 : 0 : pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
6793 : 0 : pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
6794 : : }
6795 : :
6796 : : OSL_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
6797 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6798 : :
6799 [ + + ][ + - ]: 15279 : bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
[ + - ]
6800 [ + + ][ + + ]: 15279 : if ( mpMetaFile && !bDecomposeTextRectAction )
6801 [ + - ][ + - ]: 1421 : mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
[ + - ][ + - ]
6802 : :
6803 [ + + ][ + - ]: 15279 : if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
[ - + ][ + + ]
[ + - ][ - + ]
[ + + ]
6804 : : return;
6805 : :
6806 : : // we need a graphics
6807 [ + + ][ + - ]: 9649 : if( !mpGraphics && !ImplGetGraphics() )
[ - + ][ + - ]
6808 : : return;
6809 [ + + ]: 9649 : if( mbInitClipRegion )
6810 [ + - ]: 583 : ImplInitClipRegion();
6811 [ + + ][ + + ]: 9649 : if( mbOutputClipped && !bDecomposeTextRectAction )
6812 : : return;
6813 : :
6814 : : // temporarily disable mtf action generation (ImplDrawText _does_
6815 : : // create META_TEXT_ACTIONs otherwise)
6816 : 8738 : GDIMetaFile* pMtf = mpMetaFile;
6817 [ + + ]: 8738 : if ( !bDecomposeTextRectAction )
6818 : 8335 : mpMetaFile = NULL;
6819 : :
6820 : : // #i47157# Factored out to ImplDrawText(), to be used also
6821 : : // from AddTextRectActions()
6822 : 8738 : DefaultTextLayout aDefaultLayout( *this );
6823 [ + - ][ + + ]: 8738 : ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
6824 : :
6825 : : // and enable again
6826 : 8738 : mpMetaFile = pMtf;
6827 : :
6828 [ + + ]: 8738 : if( mpAlphaVDev )
6829 [ + - ][ + - ]: 15279 : mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
6830 : : }
6831 : :
6832 : : // -----------------------------------------------------------------------
6833 : :
6834 : 2383 : Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
6835 : : const XubString& rStr, sal_uInt16 nStyle,
6836 : : TextRectInfo* pInfo,
6837 : : const ::vcl::ITextLayout* _pTextLayout ) const
6838 : : {
6839 : : OSL_TRACE( "OutputDevice::GetTextRect()" );
6840 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6841 : :
6842 : 2383 : Rectangle aRect = rRect;
6843 : : xub_StrLen nLines;
6844 [ + - ]: 2383 : long nWidth = rRect.GetWidth();
6845 : : long nMaxWidth;
6846 [ + - ]: 2383 : long nTextHeight = GetTextHeight();
6847 : :
6848 [ + - ]: 2383 : String aStr = rStr;
6849 [ + + ]: 2383 : if ( nStyle & TEXT_DRAW_MNEMONIC )
6850 [ + - ][ + - ]: 1406 : aStr = GetNonMnemonicString( aStr );
[ + - ]
6851 : :
6852 [ + + ]: 2383 : if ( nStyle & TEXT_DRAW_MULTILINE )
6853 : : {
6854 [ + - ]: 863 : ImplMultiTextLineInfo aMultiLineInfo;
6855 : : ImplTextLineInfo* pLineInfo;
6856 : : xub_StrLen nFormatLines;
6857 : : xub_StrLen i;
6858 : :
6859 : 863 : nMaxWidth = 0;
6860 : 863 : DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
6861 [ + - ][ + - ]: 863 : ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
6862 : 863 : nFormatLines = aMultiLineInfo.Count();
6863 [ - + ]: 863 : if ( !nTextHeight )
6864 : 0 : nTextHeight = 1;
6865 [ + - ]: 863 : nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
6866 [ - + ]: 863 : if ( pInfo )
6867 : 0 : pInfo->mnLineCount = nFormatLines;
6868 [ + + ]: 863 : if ( !nLines )
6869 : 8 : nLines = 1;
6870 [ + - ]: 863 : if ( nFormatLines <= nLines )
6871 : 863 : nLines = nFormatLines;
6872 : : else
6873 : : {
6874 [ # # ]: 0 : if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
6875 : 0 : nLines = nFormatLines;
6876 : : else
6877 : : {
6878 [ # # ]: 0 : if ( pInfo )
6879 : 0 : pInfo->mbEllipsis = sal_True;
6880 : 0 : nMaxWidth = nWidth;
6881 : : }
6882 : : }
6883 [ - + ]: 863 : if ( pInfo )
6884 : : {
6885 : 0 : sal_Bool bMaxWidth = nMaxWidth == 0;
6886 : 0 : pInfo->mnMaxWidth = 0;
6887 [ # # ]: 0 : for ( i = 0; i < nLines; i++ )
6888 : : {
6889 : 0 : pLineInfo = aMultiLineInfo.GetLine( i );
6890 [ # # ][ # # ]: 0 : if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
[ # # ]
6891 : 0 : nMaxWidth = pLineInfo->GetWidth();
6892 [ # # ]: 0 : if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
6893 : 0 : pInfo->mnMaxWidth = pLineInfo->GetWidth();
6894 : : }
6895 : : }
6896 [ + - ]: 863 : else if ( !nMaxWidth )
6897 : : {
6898 [ + + ]: 1491 : for ( i = 0; i < nLines; i++ )
6899 : : {
6900 : 628 : pLineInfo = aMultiLineInfo.GetLine( i );
6901 [ + + ]: 628 : if ( pLineInfo->GetWidth() > nMaxWidth )
6902 : 626 : nMaxWidth = pLineInfo->GetWidth();
6903 : : }
6904 [ + - ]: 863 : }
6905 : : }
6906 : : else
6907 : : {
6908 : 1520 : nLines = 1;
6909 [ - + ][ # # ]: 1520 : nMaxWidth = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
[ + - ]
6910 : :
6911 [ - + ]: 1520 : if ( pInfo )
6912 : : {
6913 : 0 : pInfo->mnLineCount = 1;
6914 : 0 : pInfo->mnMaxWidth = nMaxWidth;
6915 : : }
6916 : :
6917 [ + + ][ - + ]: 1520 : if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
6918 : : {
6919 [ # # ]: 0 : if ( pInfo )
6920 : 0 : pInfo->mbEllipsis = sal_True;
6921 : 0 : nMaxWidth = nWidth;
6922 : : }
6923 : : }
6924 : :
6925 [ - + ]: 2383 : if ( nStyle & TEXT_DRAW_RIGHT )
6926 : 0 : aRect.Left() = aRect.Right()-nMaxWidth+1;
6927 [ + + ]: 2383 : else if ( nStyle & TEXT_DRAW_CENTER )
6928 : : {
6929 : 243 : aRect.Left() += (nWidth-nMaxWidth)/2;
6930 : 243 : aRect.Right() = aRect.Left()+nMaxWidth-1;
6931 : : }
6932 : : else
6933 : 2140 : aRect.Right() = aRect.Left()+nMaxWidth-1;
6934 : :
6935 [ - + ]: 2383 : if ( nStyle & TEXT_DRAW_BOTTOM )
6936 : 0 : aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
6937 [ + + ]: 2383 : else if ( nStyle & TEXT_DRAW_VCENTER )
6938 : : {
6939 [ + - ]: 885 : aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2;
6940 : 885 : aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
6941 : : }
6942 : : else
6943 : 1498 : aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
6944 : :
6945 : 2383 : aRect.Right()++; // #99188# get rid of rounding problems when using this rect later
6946 [ + - ]: 2383 : return aRect;
6947 : : }
6948 : :
6949 : : // -----------------------------------------------------------------------
6950 : :
6951 : 0 : static sal_Bool ImplIsCharIn( xub_Unicode c, const sal_Char* pStr )
6952 : : {
6953 [ # # ]: 0 : while ( *pStr )
6954 : : {
6955 [ # # ]: 0 : if ( *pStr == c )
6956 : 0 : return sal_True;
6957 : 0 : pStr++;
6958 : : }
6959 : :
6960 : 0 : return sal_False;
6961 : : }
6962 : :
6963 : : // -----------------------------------------------------------------------
6964 : :
6965 : 13856 : String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
6966 : : sal_uInt16 nStyle ) const
6967 : : {
6968 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6969 : 13856 : DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
6970 [ + - ][ + - ]: 13856 : return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
6971 : : }
6972 : :
6973 : : // -----------------------------------------------------------------------
6974 : :
6975 : 13859 : String OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rOrigStr, long nMaxWidth,
6976 : : sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
6977 : : {
6978 : : OSL_TRACE( "OutputDevice::ImplGetEllipsisString()" );
6979 : :
6980 : 13859 : String aStr = rOrigStr;
6981 [ + - ]: 13859 : xub_StrLen nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.Len() );
6982 : :
6983 : :
6984 [ + + ]: 13859 : if ( nIndex != STRING_LEN )
6985 : : {
6986 [ - + ]: 5 : if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
6987 : : {
6988 [ # # ]: 0 : String aTmpStr( aStr );
6989 : 0 : xub_StrLen nEraseChars = 4;
6990 [ # # ][ # # ]: 0 : while( nEraseChars < aStr.Len() && _rLayout.GetTextWidth( aTmpStr, 0, aTmpStr.Len() ) > nMaxWidth )
[ # # ][ # # ]
6991 : : {
6992 [ # # ]: 0 : aTmpStr = aStr;
6993 : 0 : xub_StrLen i = (aTmpStr.Len() - nEraseChars)/2;
6994 [ # # ]: 0 : aTmpStr.Erase( i, nEraseChars++ );
6995 [ # # ]: 0 : aTmpStr.InsertAscii( "...", i );
6996 : : }
6997 [ # # ][ # # ]: 0 : aStr = aTmpStr;
6998 : : }
6999 [ + - ]: 5 : else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
7000 : : {
7001 [ + - ]: 5 : aStr.Erase( nIndex );
7002 [ + - ]: 5 : if ( nIndex > 1 )
7003 : : {
7004 [ + - ]: 5 : aStr.AppendAscii( "..." );
7005 [ + - ][ + - ]: 12 : while ( aStr.Len() && (_rLayout.GetTextWidth( aStr, 0, aStr.Len() ) > nMaxWidth) )
[ + + ][ + + ]
7006 : : {
7007 [ - + ][ # # ]: 7 : if ( (nIndex > 1) || (nIndex == aStr.Len()) )
[ + - ]
7008 : 7 : nIndex--;
7009 [ + - ]: 7 : aStr.Erase( nIndex, 1 );
7010 : : }
7011 : : }
7012 : :
7013 [ - + ][ # # ]: 5 : if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
[ - + ]
7014 [ # # ]: 0 : aStr += rOrigStr.GetChar( 0 );
7015 : : }
7016 [ # # ]: 0 : else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
7017 : : {
7018 [ # # ]: 0 : rtl::OUString aPath( rOrigStr );
7019 : 0 : rtl::OUString aAbbreviatedPath;
7020 [ # # ]: 0 : osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
7021 [ # # ]: 0 : aStr = aAbbreviatedPath;
7022 : : }
7023 [ # # ]: 0 : else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
7024 : : {
7025 : : static sal_Char const pSepChars[] = ".";
7026 : : // Letztes Teilstueck ermitteln
7027 : 0 : xub_StrLen nLastContent = aStr.Len();
7028 [ # # ]: 0 : while ( nLastContent )
7029 : : {
7030 : 0 : nLastContent--;
7031 [ # # ]: 0 : if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
7032 : 0 : break;
7033 : : }
7034 [ # # # # ]: 0 : while ( nLastContent &&
[ # # ]
7035 : 0 : ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
7036 : 0 : nLastContent--;
7037 : :
7038 [ # # ]: 0 : XubString aLastStr( aStr, nLastContent, aStr.Len() );
7039 [ # # ]: 0 : XubString aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
7040 [ # # ]: 0 : aTempLastStr1 += aLastStr;
7041 [ # # ][ # # ]: 0 : if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.Len() ) > nMaxWidth )
7042 [ # # ][ # # ]: 0 : aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
[ # # ]
7043 : : else
7044 : : {
7045 : 0 : sal_uInt16 nFirstContent = 0;
7046 [ # # ]: 0 : while ( nFirstContent < nLastContent )
7047 : : {
7048 : 0 : nFirstContent++;
7049 [ # # ]: 0 : if ( ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
7050 : 0 : break;
7051 : : }
7052 [ # # # # ]: 0 : while ( (nFirstContent < nLastContent) &&
[ # # ]
7053 : 0 : ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
7054 : 0 : nFirstContent++;
7055 : :
7056 [ # # ]: 0 : if ( nFirstContent >= nLastContent )
7057 [ # # ][ # # ]: 0 : aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
[ # # ]
7058 : : else
7059 : : {
7060 [ # # ]: 0 : if ( nFirstContent > 4 )
7061 : 0 : nFirstContent = 4;
7062 [ # # ]: 0 : XubString aFirstStr( aStr, 0, nFirstContent );
7063 [ # # ]: 0 : aFirstStr.AppendAscii( "..." );
7064 [ # # ]: 0 : XubString aTempStr = aFirstStr;
7065 [ # # ]: 0 : aTempStr += aLastStr;
7066 [ # # ][ # # ]: 0 : if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
7067 [ # # ][ # # ]: 0 : aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
[ # # ]
7068 : : else
7069 : : {
7070 [ # # ]: 0 : do
7071 : : {
7072 [ # # ]: 0 : aStr = aTempStr;
7073 [ # # ]: 0 : if( nLastContent > aStr.Len() )
7074 : 0 : nLastContent = aStr.Len();
7075 [ # # ]: 0 : while ( nFirstContent < nLastContent )
7076 : : {
7077 : 0 : nLastContent--;
7078 [ # # ]: 0 : if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
7079 : 0 : break;
7080 : :
7081 : : }
7082 [ # # # # ]: 0 : while ( (nFirstContent < nLastContent) &&
[ # # ]
7083 : 0 : ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
7084 : 0 : nLastContent--;
7085 : :
7086 [ # # ]: 0 : if ( nFirstContent < nLastContent )
7087 : : {
7088 [ # # ]: 0 : XubString aTempLastStr( aStr, nLastContent, aStr.Len() );
7089 [ # # ]: 0 : aTempStr = aFirstStr;
7090 [ # # ]: 0 : aTempStr += aTempLastStr;
7091 [ # # ][ # # ]: 0 : if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
7092 [ # # ][ # # ]: 0 : break;
7093 : : }
7094 : : }
7095 : : while ( nFirstContent < nLastContent );
7096 [ # # ][ # # ]: 0 : }
7097 : : }
7098 [ # # ][ # # ]: 0 : }
7099 : : }
7100 : : }
7101 : :
7102 : 13859 : return aStr;
7103 : : }
7104 : :
7105 : : // -----------------------------------------------------------------------
7106 : :
7107 : 14264 : void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
7108 : : xub_StrLen nIndex, xub_StrLen nLen,
7109 : : sal_uInt16 nStyle, MetricVector* pVector, String* pDisplayText )
7110 : : {
7111 : : OSL_TRACE( "OutputDevice::DrawCtrlText()" );
7112 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7113 : :
7114 [ + - ][ - + ]: 14264 : if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
[ + - ]
7115 : : return;
7116 : :
7117 : : // better get graphics here because ImplDrawMnemonicLine() will not
7118 : : // we need a graphics
7119 [ - + ][ # # ]: 14264 : if( !mpGraphics && !ImplGetGraphics() )
[ # # ][ + - ]
7120 : : return;
7121 [ + + ]: 14264 : if( mbInitClipRegion )
7122 [ + - ]: 1712 : ImplInitClipRegion();
7123 [ + - ]: 14264 : if ( mbOutputClipped )
7124 : : return;
7125 : :
7126 [ + - ]: 14264 : if( nIndex >= rStr.Len() )
7127 : : return;
7128 [ + - ]: 14264 : if( (sal_uLong)nIndex+nLen >= rStr.Len() )
7129 : 14264 : nLen = rStr.Len() - nIndex;
7130 : :
7131 [ + - ]: 14264 : XubString aStr = rStr;
7132 : 14264 : xub_StrLen nMnemonicPos = STRING_NOTFOUND;
7133 : :
7134 : 14264 : long nMnemonicX = 0;
7135 : 14264 : long nMnemonicY = 0;
7136 : 14264 : long nMnemonicWidth = 0;
7137 [ + + ][ + - ]: 14264 : if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
7138 : : {
7139 [ + - ][ + - ]: 14104 : aStr = GetNonMnemonicString( aStr, nMnemonicPos );
[ + - ]
7140 [ + + ]: 14104 : if ( nMnemonicPos != STRING_NOTFOUND )
7141 : : {
7142 [ - + ]: 13828 : if( nMnemonicPos < nIndex )
7143 : 0 : --nIndex;
7144 [ + - ]: 13828 : else if( nLen < STRING_LEN )
7145 : : {
7146 [ + - ]: 13828 : if( nMnemonicPos < (nIndex+nLen) )
7147 : 13828 : --nLen;
7148 : : DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
7149 : : }
7150 : 13828 : sal_Bool bInvalidPos = sal_False;
7151 : :
7152 [ - + ]: 13828 : if( nMnemonicPos >= nLen )
7153 : : {
7154 : : // #106952#
7155 : : // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
7156 : : // due to some strange BiDi text editors
7157 : : // ->place the underline behind the string to indicate a failure
7158 : 0 : bInvalidPos = sal_True;
7159 : 0 : nMnemonicPos = nLen-1;
7160 : : }
7161 : :
7162 : 13828 : sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
7163 [ + - ]: 13828 : /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
7164 : 13828 : long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
7165 : 13828 : long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
7166 : 13828 : nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
7167 : :
7168 [ + - ][ + - ]: 13828 : Point aTempPos( Min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
[ + - ]
7169 [ - + ]: 13828 : if( bInvalidPos ) // #106952#, place behind the (last) character
7170 [ # # ][ # # ]: 0 : aTempPos = Point( Max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
[ # # ]
7171 : :
7172 : 13828 : aTempPos += rPos;
7173 [ + - ]: 13828 : aTempPos = LogicToPixel( aTempPos );
7174 : 13828 : nMnemonicX = mnOutOffX + aTempPos.X();
7175 : 13828 : nMnemonicY = mnOutOffY + aTempPos.Y();
7176 : : }
7177 : : }
7178 : :
7179 [ + + ][ + + ]: 14264 : if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
7180 : : {
7181 : 158 : Color aOldTextColor;
7182 : 158 : Color aOldTextFillColor;
7183 : : sal_Bool bRestoreFillColor;
7184 : 158 : sal_Bool bHighContrastBlack = sal_False;
7185 : 158 : sal_Bool bHighContrastWhite = sal_False;
7186 : 158 : const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
7187 [ - + ]: 158 : if( rStyleSettings.GetHighContrastMode() )
7188 : : {
7189 [ # # ]: 0 : if( IsBackground() )
7190 : : {
7191 [ # # ]: 0 : Wallpaper aWall = GetBackground();
7192 [ # # ]: 0 : Color aCol = aWall.GetColor();
7193 [ # # ]: 0 : bHighContrastBlack = aCol.IsDark();
7194 [ # # ][ # # ]: 0 : bHighContrastWhite = aCol.IsBright();
7195 : : }
7196 : : }
7197 : :
7198 : 158 : aOldTextColor = GetTextColor();
7199 [ - + ][ + - ]: 158 : if ( IsTextFillColor() )
7200 : : {
7201 : 0 : bRestoreFillColor = sal_True;
7202 [ # # ]: 0 : aOldTextFillColor = GetTextFillColor();
7203 : : }
7204 : : else
7205 : 158 : bRestoreFillColor = sal_False;
7206 : :
7207 [ - + ]: 158 : if( bHighContrastBlack )
7208 [ # # ]: 0 : SetTextColor( COL_GREEN );
7209 [ - + ]: 158 : else if( bHighContrastWhite )
7210 [ # # ]: 0 : SetTextColor( COL_LIGHTGREEN );
7211 : : else
7212 [ + - ]: 158 : SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
7213 : :
7214 [ + - ]: 158 : DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
7215 [ + - ][ + - ]: 158 : if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
[ + - ]
7216 : : {
7217 [ + + ]: 158 : if ( nMnemonicPos != STRING_NOTFOUND )
7218 [ + - ]: 148 : ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
7219 : : }
7220 [ + - ]: 158 : SetTextColor( aOldTextColor );
7221 [ - + ]: 158 : if ( bRestoreFillColor )
7222 [ # # ]: 158 : SetTextFillColor( aOldTextFillColor );
7223 : : }
7224 : : else
7225 : : {
7226 [ + - ]: 14106 : DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
7227 [ + - ][ + + ]: 14106 : if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
[ + + ]
7228 : : {
7229 [ + + ]: 14056 : if ( nMnemonicPos != STRING_NOTFOUND )
7230 [ + - ]: 13630 : ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
7231 : : }
7232 : : }
7233 : :
7234 [ - + ]: 14264 : if( mpAlphaVDev )
7235 [ # # ][ + - ]: 14264 : mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
7236 : : }
7237 : :
7238 : : // -----------------------------------------------------------------------
7239 : :
7240 : 15562 : long OutputDevice::GetCtrlTextWidth( const String& rStr,
7241 : : xub_StrLen nIndex, xub_StrLen nLen,
7242 : : sal_uInt16 nStyle ) const
7243 : : {
7244 : : OSL_TRACE( "OutputDevice::GetCtrlTextSize()" );
7245 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7246 : :
7247 [ + - ]: 15562 : if ( nStyle & TEXT_DRAW_MNEMONIC )
7248 : : {
7249 : : xub_StrLen nMnemonicPos;
7250 [ + - ]: 15562 : XubString aStr = GetNonMnemonicString( rStr, nMnemonicPos );
7251 [ + + ]: 15562 : if ( nMnemonicPos != STRING_NOTFOUND )
7252 : : {
7253 [ - + ]: 11545 : if ( nMnemonicPos < nIndex )
7254 : 0 : nIndex--;
7255 [ - + ][ # # ]: 11545 : else if ( (nLen < STRING_LEN) &&
[ # # ]
7256 : : (nMnemonicPos >= nIndex) && (nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
7257 : 0 : nLen--;
7258 : : }
7259 [ + - ][ + - ]: 15562 : return GetTextWidth( aStr, nIndex, nLen );
7260 : : }
7261 : : else
7262 : 15562 : return GetTextWidth( rStr, nIndex, nLen );
7263 : : }
7264 : :
7265 : : // -----------------------------------------------------------------------
7266 : :
7267 : 55819 : String OutputDevice::GetNonMnemonicString( const String& rStr, xub_StrLen& rMnemonicPos )
7268 : : {
7269 : 55819 : String aStr = rStr;
7270 : 55819 : xub_StrLen nLen = aStr.Len();
7271 : 55819 : xub_StrLen i = 0;
7272 : :
7273 : 55819 : rMnemonicPos = STRING_NOTFOUND;
7274 [ + + ]: 373137 : while ( i < nLen )
7275 : : {
7276 [ + + ]: 317318 : if ( aStr.GetChar( i ) == '~' )
7277 : : {
7278 [ + - ]: 39549 : if ( aStr.GetChar( i+1 ) != '~' )
7279 : : {
7280 [ + - ]: 39549 : if ( rMnemonicPos == STRING_NOTFOUND )
7281 : 39549 : rMnemonicPos = i;
7282 [ + - ]: 39549 : aStr.Erase( i, 1 );
7283 : 39549 : nLen--;
7284 : : }
7285 : : else
7286 : : {
7287 [ # # ]: 0 : aStr.Erase( i, 1 );
7288 : 0 : nLen--;
7289 : 0 : i++;
7290 : : }
7291 : : }
7292 : : else
7293 : 277769 : i++;
7294 : : }
7295 : :
7296 : 55819 : return aStr;
7297 : : }
7298 : :
7299 : : // -----------------------------------------------------------------------
7300 : :
7301 : 530635 : int OutputDevice::GetDevFontCount() const
7302 : : {
7303 : : OSL_TRACE( "OutputDevice::GetDevFontCount()" );
7304 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7305 : :
7306 [ + + ]: 530635 : if( !mpGetDevFontList )
7307 : 2925 : mpGetDevFontList = mpFontList->GetDevFontList();
7308 : 530635 : return mpGetDevFontList->Count();
7309 : : }
7310 : :
7311 : : // -----------------------------------------------------------------------
7312 : :
7313 : 526410 : FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
7314 : : {
7315 : : OSL_TRACE( "OutputDevice::GetDevFont()" );
7316 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7317 : :
7318 : 526410 : FontInfo aFontInfo;
7319 : :
7320 [ + - ]: 526410 : ImplInitFontList();
7321 : :
7322 [ + - ]: 526410 : int nCount = GetDevFontCount();
7323 [ + - ]: 526410 : if( nDevFontIndex < nCount )
7324 : : {
7325 [ + - ]: 526410 : const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
7326 [ + - ][ + - ]: 526410 : aFontInfo.SetName( rData.maName );
7327 [ + - ]: 526410 : aFontInfo.SetStyleName( rData.maStyleName );
7328 [ + + ][ + - ]: 526410 : aFontInfo.SetCharSet( rData.mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
7329 [ + - ]: 526410 : aFontInfo.SetFamily( rData.meFamily );
7330 [ + - ]: 526410 : aFontInfo.SetPitch( rData.mePitch );
7331 [ + - ]: 526410 : aFontInfo.SetWeight( rData.meWeight );
7332 [ + - ]: 526410 : aFontInfo.SetItalic( rData.meItalic );
7333 [ + - ]: 526410 : aFontInfo.SetWidthType( rData.meWidthType );
7334 [ + - ]: 526410 : if( rData.IsScalable() )
7335 : 526410 : aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
7336 [ + + ]: 526410 : if( rData.mbDevice )
7337 : 1798 : aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
7338 : : }
7339 : :
7340 : 526410 : return aFontInfo;
7341 : : }
7342 : :
7343 : : // -----------------------------------------------------------------------
7344 : :
7345 : 0 : sal_Bool OutputDevice::AddTempDevFont( const String& rFileURL, const String& rFontName )
7346 : : {
7347 : : OSL_TRACE( "OutputDevice::AddTempDevFont()" );
7348 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7349 : :
7350 : 0 : ImplInitFontList();
7351 : :
7352 [ # # ][ # # ]: 0 : if( !mpGraphics && !ImplGetGraphics() )
[ # # ]
7353 : 0 : return sal_False;
7354 : :
7355 [ # # ][ # # ]: 0 : bool bRC = mpGraphics->AddTempDevFont( mpFontList, rFileURL, rFontName );
7356 [ # # ]: 0 : if( !bRC )
7357 : 0 : return sal_False;
7358 : :
7359 [ # # ]: 0 : if( mpAlphaVDev )
7360 : 0 : mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
7361 : :
7362 : 0 : mpFontCache->Invalidate();
7363 : 0 : return sal_True;
7364 : : }
7365 : :
7366 : : // -----------------------------------------------------------------------
7367 : :
7368 : 1481 : int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
7369 : : {
7370 : : OSL_TRACE( "OutputDevice::GetDevFontSizeCount()" );
7371 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7372 : :
7373 [ + + ]: 1481 : delete mpGetDevSizeList;
7374 : :
7375 : 1481 : ImplInitFontList();
7376 : 1481 : mpGetDevSizeList = mpFontList->GetDevSizeList( rFont.GetName() );
7377 : 1481 : return mpGetDevSizeList->Count();
7378 : : }
7379 : :
7380 : : // -----------------------------------------------------------------------
7381 : :
7382 : 0 : Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
7383 : : {
7384 : : OSL_TRACE( "OutputDevice::GetDevFontSize()" );
7385 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7386 : :
7387 : : // check range
7388 [ # # ]: 0 : int nCount = GetDevFontSizeCount( rFont );
7389 [ # # ]: 0 : if ( nSizeIndex >= nCount )
7390 : 0 : return Size();
7391 : :
7392 : : // when mapping is enabled round to .5 points
7393 [ # # ]: 0 : Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
7394 [ # # ]: 0 : if ( mbMap )
7395 : : {
7396 : 0 : aSize.Height() *= 10;
7397 [ # # ][ # # ]: 0 : MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
[ # # ]
7398 [ # # ]: 0 : aSize = PixelToLogic( aSize, aMap );
7399 : 0 : aSize.Height() += 5;
7400 : 0 : aSize.Height() /= 10;
7401 : 0 : long nRound = aSize.Height() % 5;
7402 [ # # ]: 0 : if ( nRound >= 3 )
7403 : 0 : aSize.Height() += (5-nRound);
7404 : : else
7405 : 0 : aSize.Height() -= nRound;
7406 : 0 : aSize.Height() *= 10;
7407 [ # # ]: 0 : aSize = LogicToPixel( aSize, aMap );
7408 [ # # ]: 0 : aSize = PixelToLogic( aSize );
7409 : 0 : aSize.Height() += 5;
7410 [ # # ]: 0 : aSize.Height() /= 10;
7411 : : }
7412 : 0 : return aSize;
7413 : : }
7414 : :
7415 : : // -----------------------------------------------------------------------
7416 : :
7417 : 45 : sal_Bool OutputDevice::IsFontAvailable( const String& rFontName ) const
7418 : : {
7419 : : OSL_TRACE( "OutputDevice::IsFontAvailable()" );
7420 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7421 : :
7422 : 45 : ImplDevFontListData* pFound = mpFontList->FindFontFamily( rFontName );
7423 : 45 : return (pFound != NULL);
7424 : : }
7425 : :
7426 : : // -----------------------------------------------------------------------
7427 : :
7428 : 509420 : FontMetric OutputDevice::GetFontMetric() const
7429 : : {
7430 : : OSL_TRACE( "OutputDevice::GetFontMetric()" );
7431 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7432 : :
7433 : 509420 : FontMetric aMetric;
7434 [ + - ][ - + ]: 509420 : if( mbNewFont && !ImplNewFont() )
[ - + ][ + + ]
7435 : 0 : return aMetric;
7436 : :
7437 : 509420 : ImplFontEntry* pEntry = mpFontEntry;
7438 : 509420 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
7439 : :
7440 : : // prepare metric
7441 [ + - ]: 509420 : aMetric.Font::operator=( maFont );
7442 : :
7443 : : // set aMetric with info from font
7444 [ + - ][ + - ]: 509420 : aMetric.SetName( maFont.GetName() );
[ + - ]
7445 [ + - ]: 509420 : aMetric.SetStyleName( pMetric->maStyleName );
7446 [ + - ][ + - ]: 509420 : aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
7447 [ + + ][ + - ]: 509420 : aMetric.SetCharSet( pMetric->mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
7448 [ + - ]: 509420 : aMetric.SetFamily( pMetric->meFamily );
7449 [ + - ]: 509420 : aMetric.SetPitch( pMetric->mePitch );
7450 [ + - ]: 509420 : aMetric.SetWeight( pMetric->meWeight );
7451 [ + - ]: 509420 : aMetric.SetItalic( pMetric->meItalic );
7452 [ + - ]: 509420 : aMetric.SetWidthType( pMetric->meWidthType );
7453 [ - + ]: 509420 : if ( pEntry->mnOwnOrientation )
7454 [ # # ]: 0 : aMetric.SetOrientation( pEntry->mnOwnOrientation );
7455 : : else
7456 [ + - ]: 509420 : aMetric.SetOrientation( pMetric->mnOrientation );
7457 [ + + ]: 509420 : if( !pEntry->maMetric.mbKernableFont )
7458 [ + - ][ + - ]: 45010 : aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
7459 : :
7460 : : // set remaining metric fields
7461 : 509420 : aMetric.mpImplMetric->mnMiscFlags = 0;
7462 [ + + ]: 509420 : if( pMetric->mbDevice )
7463 : 508823 : aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
7464 [ + - ]: 509420 : if( pMetric->mbScalableFont )
7465 : 509420 : aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
7466 [ + - ]: 509420 : aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
7467 [ + - ]: 509420 : aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
7468 [ + - ]: 509420 : aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
7469 [ + - ]: 509420 : aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
7470 [ + - ]: 509420 : aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
7471 [ + - ]: 509420 : aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
7472 : :
7473 : : #ifdef UNX
7474 : : // backwards compatible line metrics after fixing #i60945#
7475 [ + + - + ]: 1003487 : if( (meOutDevType == OUTDEV_VIRDEV)
[ - + ]
7476 : 494067 : && static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
7477 : 0 : aMetric.mpImplMetric->mnExtLeading = 0;
7478 : : #endif
7479 : :
7480 : 509420 : return aMetric;
7481 : : }
7482 : :
7483 : : // -----------------------------------------------------------------------
7484 : :
7485 : 0 : FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
7486 : : {
7487 : : // select font, query metrics, select original font again
7488 [ # # ]: 0 : Font aOldFont = GetFont();
7489 [ # # ]: 0 : const_cast<OutputDevice*>(this)->SetFont( rFont );
7490 [ # # ]: 0 : FontMetric aMetric( GetFontMetric() );
7491 [ # # ]: 0 : const_cast<OutputDevice*>(this)->SetFont( aOldFont );
7492 [ # # ]: 0 : return aMetric;
7493 : : }
7494 : :
7495 : : // -----------------------------------------------------------------------
7496 : :
7497 : : /** OutputDevice::GetSysFontData
7498 : : *
7499 : : * @param nFallbacklevel Fallback font level (0 = best matching font)
7500 : : *
7501 : : * Retrieve detailed font information in platform independent structure
7502 : : *
7503 : : * @return SystemFontData
7504 : : **/
7505 : 0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
7506 : : {
7507 : 0 : SystemFontData aSysFontData;
7508 : 0 : aSysFontData.nSize = sizeof(aSysFontData);
7509 : :
7510 [ # # ]: 0 : if (!mpGraphics) ImplGetGraphics();
7511 [ # # ]: 0 : if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
7512 : :
7513 : 0 : return aSysFontData;
7514 : : }
7515 : :
7516 : :
7517 : : // -----------------------------------------------------------------------
7518 : :
7519 : : /** OutputDevice::GetSysTextLayoutData
7520 : : *
7521 : : * @param rStartPt Start point of the text
7522 : : * @param rStr Text string that will be transformed into layout of glyphs
7523 : : * @param nIndex Position in the string from where layout will be done
7524 : : * @param nLen Length of the string
7525 : : * @param pDXAry Custom layout adjustment data
7526 : : *
7527 : : * Export finalized glyph layout data as platform independent SystemTextLayoutData
7528 : : * (see vcl/inc/vcl/sysdata.hxx)
7529 : : *
7530 : : * Only parameters rStartPt and rStr are mandatory, the rest is optional
7531 : : * (default values will be used)
7532 : : *
7533 : : * @return SystemTextLayoutData
7534 : : **/
7535 : 0 : SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen,
7536 : : const sal_Int32* pDXAry) const
7537 : : {
7538 : : OSL_TRACE( "OutputDevice::GetSysTextLayoutData()" );
7539 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7540 : :
7541 [ # # ]: 0 : SystemTextLayoutData aSysLayoutData;
7542 : 0 : aSysLayoutData.nSize = sizeof(aSysLayoutData);
7543 [ # # ]: 0 : aSysLayoutData.rGlyphData.reserve( 256 );
7544 : :
7545 [ # # ]: 0 : if ( mpMetaFile )
7546 : : {
7547 [ # # ]: 0 : if (pDXAry)
7548 [ # # ][ # # ]: 0 : mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
[ # # ][ # # ]
7549 : : else
7550 [ # # ][ # # ]: 0 : mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
[ # # ][ # # ]
7551 : : }
7552 : :
7553 [ # # ]: 0 : if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
7554 : :
7555 [ # # ]: 0 : SalLayout* pLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
7556 : :
7557 [ # # ]: 0 : if ( !pLayout ) return aSysLayoutData;
7558 : :
7559 : : // setup glyphs
7560 : 0 : Point aPos;
7561 : : sal_GlyphId aGlyphId;
7562 [ # # ][ # # ]: 0 : for( int nStart = 0; pLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
7563 : : {
7564 : : // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
7565 : : // ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
7566 : :
7567 : : SystemGlyphData aGlyph;
7568 : 0 : aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
7569 : 0 : aGlyph.x = aPos.X();
7570 : 0 : aGlyph.y = aPos.Y();
7571 : 0 : int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
7572 [ # # ]: 0 : aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
7573 [ # # ]: 0 : aSysLayoutData.rGlyphData.push_back(aGlyph);
7574 : : }
7575 : :
7576 : : // Get font data
7577 : 0 : aSysLayoutData.orientation = pLayout->GetOrientation();
7578 : :
7579 [ # # ]: 0 : pLayout->Release();
7580 : :
7581 : 0 : return aSysLayoutData;
7582 : : }
7583 : :
7584 : : // -----------------------------------------------------------------------
7585 : :
7586 : :
7587 : 0 : long OutputDevice::GetMinKashida() const
7588 : : {
7589 : : OSL_TRACE( "OutputDevice::GetMinKashida()" );
7590 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7591 [ # # ][ # # ]: 0 : if( mbNewFont && !ImplNewFont() )
[ # # ]
7592 : 0 : return 0;
7593 : :
7594 : 0 : ImplFontEntry* pEntry = mpFontEntry;
7595 : 0 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
7596 : 0 : return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
7597 : : }
7598 : :
7599 : : // -----------------------------------------------------------------------
7600 : 0 : xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
7601 : : xub_StrLen nIdx, xub_StrLen nLen,
7602 : : xub_StrLen nKashCount,
7603 : : const xub_StrLen* pKashidaPos,
7604 : : xub_StrLen* pKashidaPosDropped ) const
7605 : : {
7606 : : // do layout
7607 [ # # ]: 0 : SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
7608 [ # # ]: 0 : if( !pSalLayout )
7609 : 0 : return 0;
7610 : 0 : xub_StrLen nDropped = 0;
7611 [ # # ]: 0 : for( int i = 0; i < nKashCount; ++i )
7612 : : {
7613 [ # # ]: 0 : if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
7614 : : {
7615 : 0 : pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
7616 : 0 : ++nDropped;
7617 : : }
7618 : : }
7619 : 0 : pSalLayout->Release();
7620 : 0 : return nDropped;
7621 : : }
7622 : :
7623 : :
7624 : :
7625 : : // -----------------------------------------------------------------------
7626 : :
7627 : :
7628 : : // TODO: best is to get rid of this method completely
7629 : 0 : sal_uLong OutputDevice::GetKerningPairCount() const
7630 : : {
7631 : : OSL_TRACE( "OutputDevice::GetKerningPairCount()" );
7632 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7633 : :
7634 [ # # ][ # # ]: 0 : if( mbNewFont && !ImplNewFont() )
[ # # ]
7635 : 0 : return 0;
7636 [ # # ]: 0 : if( mbInitFont )
7637 : 0 : ImplInitFont();
7638 : :
7639 [ # # ][ # # ]: 0 : if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
[ # # ]
7640 : 0 : return 0;
7641 : :
7642 : : // get the kerning pair count from the device layer
7643 : 0 : int nKernPairs = mpGraphics->GetKernPairs( 0, NULL );
7644 : 0 : return nKernPairs;
7645 : : }
7646 : :
7647 : : // -----------------------------------------------------------------------
7648 : :
7649 : 0 : inline bool CmpKernData( const KerningPair& a, const KerningPair& b )
7650 : : {
7651 [ # # ][ # # ]: 0 : return (a.nChar1 < b.nChar1) || ((a.nChar1 == b.nChar1) && (a.nChar2 < b.nChar2));
[ # # ]
7652 : : }
7653 : :
7654 : : // TODO: best is to get rid of this method completely
7655 : 0 : void OutputDevice::GetKerningPairs( sal_uLong nRequestedPairs, KerningPair* pKernPairs ) const
7656 : : {
7657 : : OSL_TRACE( "OutputDevice::GetKerningPairs()" );
7658 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7659 : :
7660 [ # # ][ # # ]: 0 : if( mbNewFont && !ImplNewFont() )
[ # # ]
7661 : 0 : return;
7662 [ # # ]: 0 : if( mbInitFont )
7663 : 0 : ImplInitFont();
7664 : :
7665 [ # # ][ # # ]: 0 : if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
[ # # ]
7666 : 0 : return;
7667 : :
7668 : : // get the kerning pairs directly from the device layer
7669 : 0 : int nKernPairs = mpGraphics->GetKernPairs( nRequestedPairs, (ImplKernPairData*)pKernPairs );
7670 : :
7671 : : // sort kerning pairs
7672 : 0 : std::sort( pKernPairs, pKernPairs+nKernPairs, CmpKernData );
7673 : : }
7674 : :
7675 : : // -----------------------------------------------------------------------
7676 : :
7677 : 2476 : sal_Bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const String& rStr,
7678 : : int nIndex, int nLen, int nBase, MetricVector& rVector )
7679 : : {
7680 : : OSL_TRACE( "OutputDevice::GetGlyphBoundRect_CTL()" );
7681 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7682 : :
7683 : 2476 : rVector.clear();
7684 : :
7685 [ + + ]: 2476 : if( nLen == STRING_LEN )
7686 : 2424 : nLen = rStr.Len() - nIndex;
7687 : :
7688 [ + - ]: 2476 : Rectangle aRect;
7689 [ + + ]: 11444 : for( int i = 0; i < nLen; i++ )
7690 : : {
7691 [ + - ][ - + ]: 8968 : if( !GetTextBoundRect( aRect, rStr, sal::static_int_cast<xub_StrLen>(nBase), sal::static_int_cast<xub_StrLen>(nIndex+i), 1 ) )
7692 : 0 : break;
7693 [ + - ]: 8968 : aRect.Move( rOrigin.X(), rOrigin.Y() );
7694 [ + - ]: 8968 : rVector.push_back( aRect );
7695 : : }
7696 : :
7697 : 2476 : return (nLen == (int)rVector.size());
7698 : : }
7699 : :
7700 : : // -----------------------------------------------------------------------
7701 : :
7702 : 125074 : sal_Bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
7703 : : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
7704 : : sal_uLong nLayoutWidth, const sal_Int32* pDXAry ) const
7705 : : {
7706 : : OSL_TRACE( "OutputDevice::GetTextBoundRect()" );
7707 : : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7708 : :
7709 : 125074 : sal_Bool bRet = sal_False;
7710 : 125074 : rRect.SetEmpty();
7711 : :
7712 : 125074 : SalLayout* pSalLayout = NULL;
7713 : 125074 : const Point aPoint;
7714 : : // calculate offset when nBase!=nIndex
7715 : 125074 : long nXOffset = 0;
7716 [ + + ]: 125074 : if( nBase != nIndex )
7717 : : {
7718 : 7906 : xub_StrLen nStart = Min( nBase, nIndex );
7719 : 7906 : xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
7720 [ + - ]: 7906 : pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
7721 [ + - ]: 7906 : if( pSalLayout )
7722 : : {
7723 [ + - ]: 7906 : nXOffset = pSalLayout->GetTextWidth();
7724 : 7906 : nXOffset /= pSalLayout->GetUnitsPerPixel();
7725 [ + - ]: 7906 : pSalLayout->Release();
7726 : : // TODO: fix offset calculation for Bidi case
7727 [ + - ]: 7906 : if( nBase < nIndex)
7728 : 7906 : nXOffset = -nXOffset;
7729 : : }
7730 : : }
7731 : :
7732 [ + - ]: 125074 : pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
7733 [ + - ]: 125074 : Rectangle aPixelRect;
7734 [ + - ]: 125074 : if( pSalLayout )
7735 : : {
7736 [ + - ]: 125074 : bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
7737 : :
7738 [ + - ]: 125074 : if( bRet )
7739 : : {
7740 : 125074 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
7741 : :
7742 [ - + ]: 125074 : if( nWidthFactor > 1 )
7743 : : {
7744 : 0 : double fFactor = 1.0 / nWidthFactor;
7745 : 0 : aPixelRect.Left()
7746 : 0 : = static_cast< long >(aPixelRect.Left() * fFactor);
7747 : 0 : aPixelRect.Right()
7748 : 0 : = static_cast< long >(aPixelRect.Right() * fFactor);
7749 : 0 : aPixelRect.Top()
7750 : 0 : = static_cast< long >(aPixelRect.Top() * fFactor);
7751 : 0 : aPixelRect.Bottom()
7752 : 0 : = static_cast< long >(aPixelRect.Bottom() * fFactor);
7753 : : }
7754 : :
7755 : 125074 : Point aRotatedOfs( mnTextOffX, mnTextOffY );
7756 [ + - ]: 125074 : aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
7757 [ + - ]: 125074 : aPixelRect += aRotatedOfs;
7758 [ + - ]: 125074 : rRect = PixelToLogic( aPixelRect );
7759 [ + + ]: 125074 : if( mbMap )
7760 [ + - ]: 125074 : rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
7761 : : }
7762 : :
7763 [ + - ]: 125074 : pSalLayout->Release();
7764 : : }
7765 : :
7766 [ - + ][ # # ]: 125074 : if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
[ # # ]
7767 : 125074 : return bRet;
7768 : :
7769 : : // fall back to bitmap method to get the bounding rectangle,
7770 : : // so we need a monochrome virtual device with matching font
7771 [ # # ]: 0 : VirtualDevice aVDev( 1 );
7772 [ # # ]: 0 : Font aFont( GetFont() );
7773 [ # # ]: 0 : aFont.SetShadow( sal_False );
7774 [ # # ]: 0 : aFont.SetOutline( sal_False );
7775 [ # # ]: 0 : aFont.SetRelief( RELIEF_NONE );
7776 [ # # ]: 0 : aFont.SetOrientation( 0 );
7777 [ # # ]: 0 : aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
7778 [ # # ]: 0 : aVDev.SetFont( aFont );
7779 [ # # ]: 0 : aVDev.SetTextAlign( ALIGN_TOP );
7780 : :
7781 : : // layout the text on the virtual device
7782 [ # # ]: 0 : pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
7783 [ # # ]: 0 : if( !pSalLayout )
7784 : 0 : return false;
7785 : :
7786 : : // make the bitmap big enough
7787 : : // TODO: use factors when it would get too big
7788 [ # # ]: 0 : long nWidth = pSalLayout->GetTextWidth();
7789 : 0 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
7790 : 0 : Point aOffset( nWidth/2, 8 );
7791 : 0 : Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
7792 [ # # ][ # # ]: 0 : if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
[ # # ][ # # ]
7793 : 0 : return false;
7794 : :
7795 : : // draw text in black
7796 : 0 : pSalLayout->DrawBase() = aOffset;
7797 [ # # ]: 0 : aVDev.SetTextColor( Color( COL_BLACK ) );
7798 [ # # ]: 0 : aVDev.SetTextFillColor();
7799 [ # # ]: 0 : aVDev.ImplInitTextColor();
7800 [ # # ]: 0 : aVDev.ImplDrawText( *pSalLayout );
7801 [ # # ]: 0 : pSalLayout->Release();
7802 : :
7803 : : // find extents using the bitmap
7804 [ # # ]: 0 : Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
7805 [ # # ]: 0 : BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
7806 [ # # ]: 0 : if( !pAcc )
7807 : 0 : return sal_False;
7808 [ # # ]: 0 : const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
7809 : 0 : const long nW = pAcc->Width();
7810 : 0 : const long nH = pAcc->Height();
7811 : 0 : long nLeft = 0;
7812 : 0 : long nRight = 0;
7813 : :
7814 : : // find top left point
7815 : 0 : long nTop = 0;
7816 [ # # ]: 0 : for(; nTop < nH; ++nTop )
7817 : : {
7818 [ # # ]: 0 : for( nLeft = 0; nLeft < nW; ++nLeft )
7819 [ # # ][ # # ]: 0 : if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
7820 : 0 : break;
7821 [ # # ]: 0 : if( nLeft < nW )
7822 : 0 : break;
7823 : : }
7824 : :
7825 : : // find bottom right point
7826 : 0 : long nBottom = nH;
7827 [ # # ]: 0 : while( --nBottom >= nTop )
7828 : : {
7829 [ # # ]: 0 : for( nRight = nW; --nRight >= 0; )
7830 [ # # ][ # # ]: 0 : if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
7831 : 0 : break;
7832 [ # # ]: 0 : if( nRight >= 0 )
7833 : 0 : break;
7834 : : }
7835 [ # # ]: 0 : if( nRight < nLeft )
7836 : : {
7837 : 0 : long nX = nRight;
7838 : 0 : nRight = nLeft;
7839 : 0 : nLeft = nX;
7840 : : }
7841 : :
7842 [ # # ]: 0 : for( long nY = nTop; nY <= nBottom; ++nY )
7843 : : {
7844 : : // find leftmost point
7845 : : long nX;
7846 [ # # ]: 0 : for( nX = 0; nX < nLeft; ++nX )
7847 [ # # ][ # # ]: 0 : if( pAcc->GetPixel( nY, nX ) == aBlack )
7848 : 0 : break;
7849 : 0 : nLeft = nX;
7850 : :
7851 : : // find rightmost point
7852 [ # # ]: 0 : for( nX = nW; --nX > nRight; )
7853 [ # # ][ # # ]: 0 : if( pAcc->GetPixel( nY, nX ) == aBlack )
7854 : 0 : break;
7855 : 0 : nRight = nX;
7856 : : }
7857 : :
7858 [ # # ]: 0 : aBmp.ReleaseAccess( pAcc );
7859 : :
7860 [ # # ]: 0 : if( nTop <= nBottom )
7861 : : {
7862 : 0 : Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
7863 : 0 : Point aTopLeft( nLeft, nTop );
7864 : 0 : aTopLeft -= aOffset;
7865 : : // adjust to text alignment
7866 : 0 : aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
7867 : : // convert to logical coordinates
7868 [ # # ]: 0 : aSize = PixelToLogic( aSize );
7869 [ # # ]: 0 : aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
7870 [ # # ]: 0 : aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
7871 [ # # ]: 0 : rRect = Rectangle( aTopLeft, aSize );
7872 : 0 : return sal_True;
7873 : : }
7874 : :
7875 [ # # ][ # # ]: 125074 : return sal_False;
[ # # ]
7876 : : }
7877 : :
7878 : : // -----------------------------------------------------------------------
7879 : :
7880 : 1200 : sal_Bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
7881 : : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
7882 : : sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
7883 : : {
7884 : : // the fonts need to be initialized
7885 [ + + ]: 1200 : if( mbNewFont )
7886 [ + - ]: 903 : ImplNewFont();
7887 [ + + ]: 1200 : if( mbInitFont )
7888 [ + - ]: 217 : ImplInitFont();
7889 [ - + ]: 1200 : if( !mpFontEntry )
7890 : 0 : return sal_False;
7891 : :
7892 : 1200 : sal_Bool bRet = sal_False;
7893 : 1200 : rVector.clear();
7894 [ + + ]: 1200 : if( nLen == STRING_LEN )
7895 : 357 : nLen = rStr.Len() - nIndex;
7896 [ + - ]: 1200 : rVector.reserve( nLen );
7897 : :
7898 : : // we want to get the Rectangle in logical units, so to
7899 : : // avoid rounding errors we just size the font in logical units
7900 : 1200 : sal_Bool bOldMap = mbMap;
7901 [ + + ]: 1200 : if( bOldMap )
7902 : : {
7903 : 357 : const_cast<OutputDevice&>(*this).mbMap = sal_False;
7904 : 357 : const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
7905 : : }
7906 : :
7907 : 1200 : SalLayout* pSalLayout = NULL;
7908 : :
7909 : : // calculate offset when nBase!=nIndex
7910 : 1200 : long nXOffset = 0;
7911 [ - + ]: 1200 : if( nBase != nIndex )
7912 : : {
7913 : 0 : xub_StrLen nStart = Min( nBase, nIndex );
7914 : 0 : xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
7915 [ # # ]: 0 : pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nTWidth, pDXArray );
7916 [ # # ]: 0 : if( pSalLayout )
7917 : : {
7918 [ # # ]: 0 : nXOffset = pSalLayout->GetTextWidth();
7919 [ # # ]: 0 : pSalLayout->Release();
7920 : : // TODO: fix offset calculation for Bidi case
7921 [ # # ]: 0 : if( nBase > nIndex)
7922 : 0 : nXOffset = -nXOffset;
7923 : : }
7924 : : }
7925 : :
7926 [ + - ]: 1200 : pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7927 [ + - ]: 1200 : if( pSalLayout )
7928 : : {
7929 [ + - ]: 1200 : bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
7930 [ + + ]: 1200 : if( bRet )
7931 : : {
7932 : : // transform polygon to pixel units
7933 [ + - ]: 1062 : ::basegfx::B2DHomMatrix aMatrix;
7934 : :
7935 : 1062 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
7936 [ - + ]: 1062 : if( nXOffset | mnTextOffX | mnTextOffY )
7937 : : {
7938 : 0 : Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
7939 [ # # ]: 0 : aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
7940 [ # # ]: 0 : aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
7941 : : }
7942 : :
7943 [ - + ]: 1062 : if( nWidthFactor > 1 )
7944 : : {
7945 : 0 : double fFactor = 1.0 / nWidthFactor;
7946 [ # # ]: 0 : aMatrix.scale( fFactor, fFactor );
7947 : : }
7948 : :
7949 [ + - ][ - + ]: 1062 : if( !aMatrix.isIdentity() )
7950 : : {
7951 : 0 : ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
7952 [ # # ][ # # ]: 0 : for(; aIt != rVector.end(); ++aIt )
[ # # ]
7953 [ # # ][ # # ]: 0 : (*aIt).transform( aMatrix );
7954 [ + - ]: 1062 : }
7955 : : }
7956 : :
7957 [ + - ]: 1200 : pSalLayout->Release();
7958 : : }
7959 : :
7960 [ + + ]: 1200 : if( bOldMap )
7961 : : {
7962 : : // restore original font size and map mode
7963 : 357 : const_cast<OutputDevice&>(*this).mbMap = bOldMap;
7964 : 357 : const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
7965 : : }
7966 : :
7967 [ + + ][ + - ]: 1200 : if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
[ - + ]
7968 : 1062 : return bRet;
7969 : :
7970 : : // fall back to bitmap conversion ------------------------------------------
7971 : :
7972 : : // Here, we can savely assume that the mapping between characters and glyphs
7973 : : // is one-to-one. This is most probably valid for the old bitmap fonts.
7974 : :
7975 : : // fall back to bitmap method to get the bounding rectangle,
7976 : : // so we need a monochrome virtual device with matching font
7977 [ + - ]: 138 : pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7978 [ - + ]: 138 : if (pSalLayout == 0)
7979 : 0 : return false;
7980 [ + - ]: 138 : long nOrgWidth = pSalLayout->GetTextWidth();
7981 : : long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
7982 : 138 : + mnEmphasisDescent;
7983 [ + - ]: 138 : pSalLayout->Release();
7984 : :
7985 [ + - ]: 138 : VirtualDevice aVDev(1);
7986 : :
7987 [ + - ]: 138 : Font aFont(GetFont());
7988 [ + - ]: 138 : aFont.SetShadow(false);
7989 [ + - ]: 138 : aFont.SetOutline(false);
7990 [ + - ]: 138 : aFont.SetRelief(RELIEF_NONE);
7991 [ + - ]: 138 : aFont.SetOrientation(0);
7992 [ + - ]: 138 : if( bOptimize )
7993 : : {
7994 [ + - ]: 138 : aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
7995 [ + - ][ + - ]: 138 : aVDev.SetMapMode( MAP_PIXEL );
[ + - ]
7996 : : }
7997 [ + - ]: 138 : aVDev.SetFont( aFont );
7998 [ + - ]: 138 : aVDev.SetTextAlign( ALIGN_TOP );
7999 [ + - ]: 138 : aVDev.SetTextColor( Color(COL_BLACK) );
8000 [ + - ]: 138 : aVDev.SetTextFillColor();
8001 : :
8002 [ + - ]: 138 : pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
8003 [ - + ]: 138 : if (pSalLayout == 0)
8004 : 0 : return false;
8005 [ + - ]: 138 : long nWidth = pSalLayout->GetTextWidth();
8006 : : long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
8007 : 138 : + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
8008 [ + - ]: 138 : pSalLayout->Release();
8009 : :
8010 [ + + ][ - + ]: 138 : if( !nWidth || !nHeight )
8011 : 33 : return sal_True;
8012 : 105 : double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
8013 : 105 : double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
8014 : :
8015 : : // calculate offset when nBase!=nIndex
8016 : : // TODO: fix offset calculation for Bidi case
8017 : 105 : nXOffset = 0;
8018 [ - + ]: 105 : if( nBase != nIndex )
8019 : : {
8020 [ # # ]: 0 : xub_StrLen nStart = ((nBase < nIndex) ? nBase : nIndex);
8021 [ # # ]: 0 : xub_StrLen nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
8022 [ # # ]: 0 : pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nTWidth, pDXArray );
8023 [ # # ]: 0 : if( pSalLayout )
8024 : : {
8025 [ # # ]: 0 : nXOffset = pSalLayout->GetTextWidth();
8026 [ # # ]: 0 : pSalLayout->Release();
8027 [ # # ]: 0 : if( nBase > nIndex)
8028 : 0 : nXOffset = -nXOffset;
8029 : : }
8030 : : }
8031 : :
8032 : 105 : bRet = true;
8033 : 105 : bool bRTL = false;
8034 [ + - ]: 105 : String aStr( rStr ); // prepare for e.g. localized digits
8035 [ + - ]: 105 : ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
8036 [ + - ][ + + ]: 210 : for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
8037 : : {
8038 : 105 : bool bSuccess = false;
8039 : :
8040 : : // draw character into virtual device
8041 [ + - ]: 105 : pSalLayout = aVDev.ImplLayout( rStr, static_cast< xub_StrLen >(nCharPos), 1, Point(0,0), nTWidth, pDXArray );
8042 [ - + ]: 105 : if (pSalLayout == 0)
8043 : 0 : return false;
8044 [ + - ]: 105 : long nCharWidth = pSalLayout->GetTextWidth();
8045 : :
8046 : 105 : Point aOffset(nCharWidth / 2, 8);
8047 : 105 : Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
8048 [ + - ]: 105 : bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
8049 [ + - ]: 105 : if( bSuccess )
8050 : : {
8051 : : // draw glyph into virtual device
8052 [ + - ]: 105 : aVDev.Erase();
8053 : 105 : pSalLayout->DrawBase() += aOffset;
8054 : 105 : pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
8055 [ + - ]: 105 : pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
8056 [ + - ]: 105 : pSalLayout->Release();
8057 : :
8058 : : // convert character image into outline
8059 [ + - ]: 105 : Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
8060 : :
8061 [ + - ]: 105 : PolyPolygon aPolyPoly;
8062 [ + - ]: 105 : bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
8063 [ - + ]: 105 : if( !bVectorized )
8064 : 0 : bSuccess = false;
8065 : : else
8066 : : {
8067 : : // convert units to logical width
8068 [ + - ][ - + ]: 105 : for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
8069 : : {
8070 [ # # ]: 0 : Polygon& rPoly = aPolyPoly[j];
8071 [ # # ][ # # ]: 0 : for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
8072 : : {
8073 [ # # ]: 0 : Point& rPt = rPoly[k];
8074 : 0 : rPt -= aOffset;
8075 : 0 : int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
8076 : 0 : int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
8077 [ # # ]: 0 : rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
8078 [ # # ]: 0 : rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
8079 : : }
8080 : : }
8081 : :
8082 : :
8083 : : // ignore "empty" glyphs:
8084 [ + - ][ - + ]: 105 : if( aPolyPoly.Count() > 0 )
8085 : : {
8086 : : // convert to B2DPolyPolygon
8087 : : // TODO: get rid of intermediate tool's PolyPolygon
8088 [ # # ]: 0 : ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
8089 [ # # ]: 0 : ::basegfx::B2DHomMatrix aMatrix;
8090 [ # # ]: 0 : aMatrix.scale( fScaleX, fScaleY );
8091 [ # # ]: 0 : int nAngle = GetFont().GetOrientation();
8092 [ # # ]: 0 : if( nAngle )
8093 [ # # ]: 0 : aMatrix.rotate( nAngle * F_PI1800 );
8094 [ # # ]: 0 : aB2DPolyPoly.transform( aMatrix );
8095 [ # # ][ # # ]: 0 : rVector.push_back( aB2DPolyPoly );
[ # # ]
8096 : : }
8097 [ + - ][ + - ]: 105 : }
8098 : : }
8099 : :
8100 : 105 : nXOffset += nCharWidth;
8101 [ + - ][ + - ]: 105 : bRet = bRet && bSuccess;
8102 : : }
8103 : :
8104 [ + - ][ + - ]: 1200 : return bRet;
[ + - ]
8105 : : }
8106 : :
8107 : : // -----------------------------------------------------------------------
8108 : :
8109 : 357 : sal_Bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
8110 : : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex,
8111 : : xub_StrLen nLen, sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
8112 : : {
8113 : 357 : rResultVector.clear();
8114 : :
8115 : : // get the basegfx polypolygon vector
8116 [ + - ]: 357 : ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
8117 [ - + ]: 357 : if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
8118 [ + - ]: 357 : bOptimize, nTWidth, pDXArray ) )
8119 : 0 : return sal_False;
8120 : :
8121 : : // convert to a tool polypolygon vector
8122 [ + - ]: 357 : rResultVector.reserve( aB2DPolyPolyVector.size() );
8123 [ + - ]: 357 : ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
8124 [ + - ][ + - ]: 576 : for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
[ + + ]
8125 [ + - ][ + - ]: 219 : rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
[ + - ][ + - ]
8126 : :
8127 : 357 : return sal_True;
8128 : : }
8129 : :
8130 : : // -----------------------------------------------------------------------
8131 : :
8132 : 0 : sal_Bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly,
8133 : : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
8134 : : sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
8135 : : {
8136 [ # # ]: 0 : rPolyPoly.Clear();
8137 : :
8138 : : // get the basegfx polypolygon vector
8139 [ # # ]: 0 : ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
8140 [ # # ]: 0 : if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
8141 [ # # ]: 0 : bOptimize, nTWidth, pDXArray ) )
8142 : 0 : return sal_False;
8143 : :
8144 : : // convert and merge into a tool polypolygon
8145 [ # # ]: 0 : ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
8146 [ # # ][ # # ]: 0 : for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
[ # # ]
8147 [ # # ][ # # ]: 0 : for( unsigned int i = 0; i < aIt->count(); ++i )
[ # # ]
8148 [ # # ][ # # ]: 0 : rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
[ # # ][ # # ]
[ # # ][ # # ]
8149 : :
8150 : 0 : return sal_True;
8151 : : }
8152 : :
8153 : 2 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
8154 : : {
8155 : : // we need a graphics
8156 [ - + ][ # # ]: 2 : if( !mpGraphics && !ImplGetGraphics() )
[ - + ]
8157 : 0 : return false;
8158 : :
8159 [ - + ]: 2 : if( mbNewFont )
8160 : 0 : ImplNewFont();
8161 [ - + ]: 2 : if( mbInitFont )
8162 : 0 : ImplInitFont();
8163 [ - + ]: 2 : if( !mpFontEntry )
8164 : 0 : return false;
8165 : :
8166 : 2 : return mpGraphics->GetImplFontCapabilities(rFontCapabilities);
8167 : : }
8168 : :
8169 : : // -----------------------------------------------------------------------
8170 : :
8171 : 6520 : sal_Bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
8172 : : {
8173 : 6520 : rFontCharMap.Reset();
8174 : :
8175 : : // we need a graphics
8176 [ # # ][ - + ]: 6520 : if( !mpGraphics && !ImplGetGraphics() )
[ - + ]
8177 : 0 : return sal_False;
8178 : :
8179 [ + + ]: 6520 : if( mbNewFont )
8180 : 5527 : ImplNewFont();
8181 [ + + ]: 6520 : if( mbInitFont )
8182 : 159 : ImplInitFont();
8183 [ - + ]: 6520 : if( !mpFontEntry )
8184 : 0 : return sal_False;
8185 : :
8186 : : #ifdef ENABLE_IFC_CACHE // a little font charmap cache helps considerably
8187 : : static const int NMAXITEMS = 16;
8188 : : static int nUsedItems = 0, nCurItem = 0;
8189 : :
8190 : : struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; };
8191 : : static CharMapCacheItem aCache[ NMAXITEMS ];
8192 : :
8193 : : const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData;
8194 : :
8195 : : int i;
8196 : : for( i = nUsedItems; --i >= 0; )
8197 : : if( pFontData == aCache[i].mpFontData )
8198 : : break;
8199 : : if( i >= 0 ) // found in cache
8200 : : {
8201 : : rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
8202 : : }
8203 : : else // need to cache
8204 : : #endif // ENABLE_IFC_CACHE
8205 : : {
8206 : 6520 : const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
8207 : 6520 : rFontCharMap.Reset( pNewMap );
8208 : :
8209 : : #ifdef ENABLE_IFC_CACHE
8210 : : // manage cache round-robin and insert data
8211 : : CharMapCacheItem& rItem = aCache[ nCurItem ];
8212 : : rItem.mpFontData = pFontData;
8213 : : rItem.maCharMap.Reset( pNewMap );
8214 : :
8215 : : if( ++nCurItem >= NMAXITEMS )
8216 : : nCurItem = 0;
8217 : :
8218 : : if( ++nUsedItems >= NMAXITEMS )
8219 : : nUsedItems = NMAXITEMS;
8220 : : #endif // ENABLE_IFC_CACHE
8221 : : }
8222 : :
8223 [ - + ]: 6520 : if( rFontCharMap.IsDefaultMap() )
8224 : 0 : return sal_False;
8225 : 6520 : return sal_True;
8226 : : }
8227 : :
8228 : : // -----------------------------------------------------------------------
8229 : :
8230 : 4624 : xub_StrLen OutputDevice::HasGlyphs( const Font& rTempFont, const String& rStr,
8231 : : xub_StrLen nIndex, xub_StrLen nLen ) const
8232 : : {
8233 [ - + ]: 4624 : if( nIndex >= rStr.Len() )
8234 : 0 : return nIndex;
8235 : 4624 : xub_StrLen nEnd = nIndex + nLen;
8236 [ + + ]: 4624 : if( (sal_uLong)nIndex+nLen > rStr.Len() )
8237 : 187 : nEnd = rStr.Len();
8238 : :
8239 : : DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
8240 : : DBG_ASSERT( nEnd <= rStr.Len(), "String too short" );
8241 : :
8242 : : // to get the map temporarily set font
8243 [ + - ]: 4624 : const Font aOrigFont = GetFont();
8244 [ + - ]: 4624 : const_cast<OutputDevice&>(*this).SetFont( rTempFont );
8245 [ + - ]: 4624 : FontCharMap aFontCharMap;
8246 [ + - ]: 4624 : sal_Bool bRet = GetFontCharMap( aFontCharMap );
8247 [ + - ]: 4624 : const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
8248 : :
8249 : : // if fontmap is unknown assume it doesn't have the glyphs
8250 [ - + ]: 4624 : if( bRet == sal_False )
8251 : 0 : return nIndex;
8252 : :
8253 : 4624 : const sal_Unicode* pStr = rStr.GetBuffer();
8254 [ + + ]: 14103 : for( pStr += nIndex; nIndex < nEnd; ++pStr, ++nIndex )
8255 [ + - ][ + + ]: 13904 : if( ! aFontCharMap.HasChar( *pStr ) )
8256 : 4425 : return nIndex;
8257 : :
8258 [ + - ][ + - ]: 4624 : return STRING_LEN;
8259 : : }
8260 : :
8261 : : // -----------------------------------------------------------------------
8262 : :
8263 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|