Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "i18npool/mslangid.hxx"
21 : #include "i18npool/languagetag.hxx"
22 :
23 : #include "rtl/tencinfo.h"
24 : #include "rtl/logfile.hxx"
25 :
26 : #include "tools/debug.hxx"
27 : #include "tools/poly.hxx"
28 :
29 : #include "basegfx/polygon/b2dpolygon.hxx"
30 : #include "basegfx/polygon/b2dpolypolygon.hxx"
31 : #include "basegfx/matrix/b2dhommatrix.hxx"
32 :
33 : #include "vcl/metric.hxx"
34 : #include "vcl/metaact.hxx"
35 : #include "vcl/gdimtf.hxx"
36 : #include "vcl/virdev.hxx"
37 : #include "vcl/print.hxx"
38 : #include "vcl/event.hxx"
39 : #include "vcl/window.hxx"
40 : #include "vcl/svapp.hxx"
41 : #include "vcl/bmpacc.hxx"
42 : #include "vcl/outdev.hxx"
43 : #include "vcl/edit.hxx"
44 : // declare system types in sysdata.hxx
45 : #include <svsys.h>
46 : #include "vcl/sysdata.hxx"
47 : #include "vcl/unohelp.hxx"
48 : #include "vcl/controllayout.hxx"
49 :
50 : #include "salgdi.hxx"
51 : #include "sallayout.hxx"
52 : #include "svdata.hxx"
53 : #include "impfont.hxx"
54 : #include "outdata.hxx"
55 : #include "outfont.hxx"
56 : #include "outdev.h"
57 : #include "textlayout.hxx"
58 : #include "svids.hrc"
59 : #include "window.h"
60 :
61 : #include "unotools/fontcvt.hxx"
62 : #include "unotools/fontcfg.hxx"
63 :
64 : #include "osl/file.h"
65 :
66 : #include <config_graphite.h>
67 : #ifdef ENABLE_GRAPHITE
68 : #include "graphite_features.hxx"
69 : #endif
70 :
71 : #include "pdfwriter_impl.hxx"
72 :
73 : #include "com/sun/star/beans/PropertyValues.hpp"
74 : #include "com/sun/star/i18n/XBreakIterator.hpp"
75 : #include "com/sun/star/i18n/WordType.hpp"
76 : #include "com/sun/star/linguistic2/LinguServiceManager.hpp"
77 : #include <comphelper/processfactory.hxx>
78 :
79 : #if defined UNX
80 : #define GLYPH_FONT_HEIGHT 128
81 : #else
82 : #define GLYPH_FONT_HEIGHT 256
83 : #endif
84 :
85 : #include "sal/alloca.h"
86 :
87 : #include <cmath>
88 : #include <cstring>
89 :
90 : #include <memory>
91 : #include <algorithm>
92 :
93 :
94 : // =======================================================================
95 :
96 : DBG_NAMEEX( OutputDevice )
97 : DBG_NAMEEX( Font )
98 :
99 : // =======================================================================
100 :
101 : using namespace ::com::sun::star;
102 : using namespace ::com::sun::star::uno;
103 : using namespace ::rtl;
104 : using namespace ::vcl;
105 : using namespace ::utl;
106 :
107 : // =======================================================================
108 :
109 : #define TEXT_DRAW_ELLIPSIS (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
110 :
111 : // =======================================================================
112 :
113 : #define UNDERLINE_LAST UNDERLINE_BOLDWAVE
114 : #define STRIKEOUT_LAST STRIKEOUT_X
115 :
116 : // =======================================================================
117 :
118 529 : static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
119 : int nOrientation )
120 : {
121 529 : if ( (nOrientation >= 0) && !(nOrientation % 900) )
122 : {
123 529 : if ( (nOrientation >= 3600) )
124 0 : nOrientation %= 3600;
125 :
126 529 : if ( nOrientation )
127 : {
128 529 : rX -= nOriginX;
129 529 : rY -= nOriginY;
130 :
131 529 : if ( nOrientation == 900 )
132 : {
133 529 : long nTemp = rX;
134 529 : rX = rY;
135 529 : rY = -nTemp;
136 : }
137 0 : else if ( nOrientation == 1800 )
138 : {
139 0 : rX = -rX;
140 0 : rY = -rY;
141 : }
142 : else /* ( nOrientation == 2700 ) */
143 : {
144 0 : long nTemp = rX;
145 0 : rX = -rY;
146 0 : rY = nTemp;
147 : }
148 :
149 529 : rX += nOriginX;
150 529 : rY += nOriginY;
151 529 : }
152 : }
153 : else
154 : {
155 0 : double nRealOrientation = nOrientation*F_PI1800;
156 0 : double nCos = cos( nRealOrientation );
157 0 : double nSin = sin( nRealOrientation );
158 :
159 : // Translation...
160 0 : long nX = rX-nOriginX;
161 0 : long nY = rY-nOriginY;
162 :
163 : // Rotation...
164 0 : rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
165 0 : rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
166 : }
167 529 : }
168 :
169 : // =======================================================================
170 :
171 2 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
172 : {
173 : // the currently selected logical font is no longer needed
174 2 : if ( mpFontEntry )
175 : {
176 0 : mpFontCache->Release( mpFontEntry );
177 0 : mpFontEntry = NULL;
178 : }
179 :
180 2 : mbInitFont = true;
181 2 : mbNewFont = true;
182 :
183 2 : if ( bNewFontLists )
184 : {
185 2 : if ( mpGetDevFontList )
186 : {
187 0 : delete mpGetDevFontList;
188 0 : mpGetDevFontList = NULL;
189 : }
190 2 : if ( mpGetDevSizeList )
191 : {
192 0 : delete mpGetDevSizeList;
193 0 : mpGetDevSizeList = NULL;
194 : }
195 :
196 : // release all physically selected fonts on this device
197 2 : if( ImplGetGraphics() )
198 2 : mpGraphics->ReleaseFonts();
199 : }
200 :
201 2 : if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
202 : {
203 2 : ImplSVData* pSVData = ImplGetSVData();
204 :
205 2 : if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
206 0 : mpFontCache->Invalidate();
207 :
208 2 : if ( bNewFontLists )
209 : {
210 : // we need a graphics
211 2 : if ( ImplGetGraphics() )
212 : {
213 2 : if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
214 0 : mpFontList->Clear();
215 :
216 2 : if( mpPDFWriter )
217 : {
218 0 : if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
219 0 : delete mpFontList;
220 0 : if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
221 0 : delete mpFontCache;
222 0 : mpFontList = mpPDFWriter->filterDevFontList( pSVData->maGDIData.mpScreenFontList );
223 0 : mpFontCache = new ImplFontCache( sal_False );
224 : }
225 : else
226 : {
227 2 : if( mpOutDevData )
228 0 : mpOutDevData->maDevFontSubst.Clear();
229 2 : mpGraphics->GetDevFontList( mpFontList );
230 2 : mpGraphics->GetDevFontSubstList( this );
231 : }
232 : }
233 : }
234 : }
235 :
236 : // also update child windows if needed
237 2 : if ( GetOutDevType() == OUTDEV_WINDOW )
238 : {
239 0 : Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
240 0 : while ( pChild )
241 : {
242 0 : pChild->ImplUpdateFontData( true );
243 0 : pChild = pChild->mpWindowImpl->mpNext;
244 : }
245 : }
246 2 : }
247 :
248 : // -----------------------------------------------------------------------
249 :
250 0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
251 : {
252 0 : ImplSVData* pSVData = ImplGetSVData();
253 :
254 : // update all windows
255 0 : Window* pFrame = pSVData->maWinData.mpFirstFrame;
256 0 : while ( pFrame )
257 : {
258 0 : pFrame->ImplUpdateFontData( bNewFontLists );
259 :
260 0 : Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
261 0 : while ( pSysWin )
262 : {
263 0 : pSysWin->ImplUpdateFontData( bNewFontLists );
264 0 : pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
265 : }
266 :
267 0 : pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
268 : }
269 :
270 : // update all virtual devices
271 0 : VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
272 0 : while ( pVirDev )
273 : {
274 0 : pVirDev->ImplUpdateFontData( bNewFontLists );
275 0 : pVirDev = pVirDev->mpNext;
276 : }
277 :
278 : // update all printers
279 0 : Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
280 0 : while ( pPrinter )
281 : {
282 0 : pPrinter->ImplUpdateFontData( bNewFontLists );
283 0 : pPrinter = pPrinter->mpNext;
284 : }
285 :
286 : // clear global font lists to have them updated
287 0 : pSVData->maGDIData.mpScreenFontCache->Invalidate();
288 0 : if ( bNewFontLists )
289 : {
290 0 : pSVData->maGDIData.mpScreenFontList->Clear();
291 0 : pFrame = pSVData->maWinData.mpFirstFrame;
292 0 : if ( pFrame )
293 : {
294 0 : if ( pFrame->ImplGetGraphics() )
295 : {
296 : // MT: Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler.
297 0 : OutputDevice *pDevice = (OutputDevice*)pFrame;
298 0 : pDevice->mpGraphics->ClearDevFontCache();
299 0 : pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontList);
300 : }
301 : }
302 : }
303 0 : }
304 :
305 : // =======================================================================
306 :
307 :
308 : // =======================================================================
309 :
310 : // TODO: remove this method when the CWS-gfbfcfg dust has settled
311 0 : void ImplFreeOutDevFontData()
312 0 : {}
313 :
314 : // =======================================================================
315 :
316 0 : void OutputDevice::BeginFontSubstitution()
317 : {
318 0 : ImplSVData* pSVData = ImplGetSVData();
319 0 : pSVData->maGDIData.mbFontSubChanged = sal_False;
320 0 : }
321 :
322 : // -----------------------------------------------------------------------
323 :
324 0 : void OutputDevice::EndFontSubstitution()
325 : {
326 0 : ImplSVData* pSVData = ImplGetSVData();
327 0 : if ( pSVData->maGDIData.mbFontSubChanged )
328 : {
329 0 : ImplUpdateAllFontData( false );
330 :
331 0 : Application* pApp = GetpApp();
332 0 : DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
333 0 : pApp->DataChanged( aDCEvt );
334 0 : pApp->NotifyAllWindows( aDCEvt );
335 0 : pSVData->maGDIData.mbFontSubChanged = sal_False;
336 : }
337 0 : }
338 :
339 : // -----------------------------------------------------------------------
340 :
341 0 : void OutputDevice::AddFontSubstitute( const XubString& rFontName,
342 : const XubString& rReplaceFontName,
343 : sal_uInt16 nFlags )
344 : {
345 0 : ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
346 0 : if( !rpSubst )
347 0 : rpSubst = new ImplDirectFontSubstitution();
348 0 : rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
349 0 : ImplGetSVData()->maGDIData.mbFontSubChanged = sal_True;
350 0 : }
351 :
352 : // -----------------------------------------------------------------------
353 :
354 0 : void ImplDirectFontSubstitution::AddFontSubstitute( const String& rFontName,
355 : const String& rSubstFontName, sal_uInt16 nFlags )
356 : {
357 0 : maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
358 0 : }
359 :
360 : // -----------------------------------------------------------------------
361 :
362 0 : ImplFontSubstEntry::ImplFontSubstEntry( const String& rFontName,
363 : const String& rSubstFontName, sal_uInt16 nSubstFlags )
364 : : maName( rFontName )
365 : , maReplaceName( rSubstFontName )
366 0 : , mnFlags( nSubstFlags )
367 : {
368 0 : maSearchName = rFontName;
369 0 : maSearchReplaceName = rSubstFontName;
370 0 : GetEnglishSearchFontName( maSearchName );
371 0 : GetEnglishSearchFontName( maSearchReplaceName );
372 0 : }
373 :
374 : // -----------------------------------------------------------------------
375 :
376 0 : void OutputDevice::ImplAddDevFontSubstitute( const XubString& rFontName,
377 : const XubString& rReplaceFontName,
378 : sal_uInt16 nFlags )
379 : {
380 0 : ImplInitOutDevData();
381 0 : mpOutDevData->maDevFontSubst.AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
382 0 : }
383 :
384 : // -----------------------------------------------------------------------
385 :
386 0 : void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
387 : {
388 0 : ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
389 0 : if( pSubst )
390 0 : pSubst->RemoveFontSubstitute( n );
391 0 : }
392 :
393 : // -----------------------------------------------------------------------
394 :
395 0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
396 : {
397 0 : FontSubstList::iterator it = maFontSubstList.begin();
398 0 : for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
399 0 : if( it != maFontSubstList.end() )
400 0 : maFontSubstList.erase( it );
401 0 : }
402 :
403 : // -----------------------------------------------------------------------
404 :
405 0 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
406 : {
407 0 : const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
408 0 : if( !pSubst )
409 0 : return 0;
410 0 : int nCount = pSubst->GetFontSubstituteCount();
411 0 : return (sal_uInt16)nCount;
412 : }
413 :
414 : // -----------------------------------------------------------------------
415 :
416 2202 : bool ImplDirectFontSubstitution::FindFontSubstitute( String& rSubstName,
417 : const String& rSearchName, sal_uInt16 nFlags ) const
418 : {
419 : // TODO: get rid of O(N) searches
420 2202 : FontSubstList::const_iterator it = maFontSubstList.begin();
421 2202 : for(; it != maFontSubstList.end(); ++it )
422 : {
423 0 : const ImplFontSubstEntry& rEntry = *it;
424 0 : if( ((rEntry.mnFlags & nFlags) || !nFlags)
425 0 : && (rEntry.maSearchName == rSearchName) )
426 : {
427 0 : rSubstName = rEntry.maSearchReplaceName;
428 0 : return true;
429 : }
430 : }
431 :
432 2202 : return false;
433 : }
434 :
435 : // -----------------------------------------------------------------------
436 :
437 73012 : static void ImplFontSubstitute( String& rFontName,
438 : sal_uInt16 nFlags, ImplDirectFontSubstitution* pDevSpecific )
439 : {
440 : #ifdef DBG_UTIL
441 : String aTempName = rFontName;
442 : GetEnglishSearchFontName( aTempName );
443 : DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
444 : #endif
445 :
446 73012 : String aSubstFontName;
447 :
448 : // apply user-configurable font replacement (eg, from the list in Tools->Options)
449 73012 : const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
450 73012 : if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
451 : {
452 0 : rFontName = aSubstFontName;
453 : return;
454 : }
455 :
456 : // apply device specific font replacement (e.g. to use printer builtin fonts)
457 73012 : if( !pDevSpecific )
458 : return;
459 :
460 2202 : if( pDevSpecific->FindFontSubstitute( aSubstFontName, rFontName, nFlags ) )
461 : {
462 0 : rFontName = aSubstFontName;
463 : return;
464 73012 : }
465 : }
466 :
467 : // -----------------------------------------------------------------------
468 :
469 15788 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
470 : sal_uLong nFlags, const OutputDevice* pOutDev )
471 : {
472 : OSL_TRACE( "OutputDevice::GetDefaultFont()" );
473 :
474 15788 : com::sun::star::lang::Locale aLocale;
475 15788 : if( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW )
476 : {
477 91 : aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
478 : }
479 : else
480 : {
481 15697 : aLocale = LanguageTag( eLang ).getLocale();
482 : }
483 :
484 15788 : utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
485 15788 : String aSearch = rDefaults.getUserInterfaceFont( aLocale ); // ensure a fallback
486 15788 : String aDefault = rDefaults.getDefaultFont( aLocale, nType );
487 15788 : if( aDefault.Len() )
488 15175 : aSearch = aDefault;
489 :
490 15788 : int nDefaultHeight = 12;
491 :
492 15788 : Font aFont;
493 15788 : aFont.SetPitch( PITCH_VARIABLE );
494 :
495 15788 : switch ( nType )
496 : {
497 : case DEFAULTFONT_SANS_UNICODE:
498 : case DEFAULTFONT_UI_SANS:
499 0 : aFont.SetFamily( FAMILY_SWISS );
500 0 : break;
501 :
502 : case DEFAULTFONT_SANS:
503 : case DEFAULTFONT_LATIN_HEADING:
504 : case DEFAULTFONT_LATIN_SPREADSHEET:
505 : case DEFAULTFONT_LATIN_DISPLAY:
506 815 : aFont.SetFamily( FAMILY_SWISS );
507 815 : break;
508 :
509 : case DEFAULTFONT_SERIF:
510 : case DEFAULTFONT_LATIN_TEXT:
511 : case DEFAULTFONT_LATIN_PRESENTATION:
512 4575 : aFont.SetFamily( FAMILY_ROMAN );
513 4575 : break;
514 :
515 : case DEFAULTFONT_FIXED:
516 : case DEFAULTFONT_LATIN_FIXED:
517 : case DEFAULTFONT_UI_FIXED:
518 72 : aFont.SetPitch( PITCH_FIXED );
519 72 : aFont.SetFamily( FAMILY_MODERN );
520 72 : break;
521 :
522 : case DEFAULTFONT_SYMBOL:
523 0 : aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
524 0 : break;
525 :
526 : case DEFAULTFONT_CJK_TEXT:
527 : case DEFAULTFONT_CJK_PRESENTATION:
528 : case DEFAULTFONT_CJK_SPREADSHEET:
529 : case DEFAULTFONT_CJK_HEADING:
530 : case DEFAULTFONT_CJK_DISPLAY:
531 5163 : aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
532 5163 : break;
533 :
534 : case DEFAULTFONT_CTL_TEXT:
535 : case DEFAULTFONT_CTL_PRESENTATION:
536 : case DEFAULTFONT_CTL_SPREADSHEET:
537 : case DEFAULTFONT_CTL_HEADING:
538 : case DEFAULTFONT_CTL_DISPLAY:
539 5163 : aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
540 5163 : break;
541 : }
542 :
543 15788 : if ( aSearch.Len() )
544 : {
545 15788 : aFont.SetHeight( nDefaultHeight );
546 15788 : aFont.SetWeight( WEIGHT_NORMAL );
547 15788 : aFont.SetLanguage( eLang );
548 :
549 15788 : if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
550 15788 : aFont.SetCharSet( osl_getThreadTextEncoding() );
551 :
552 : // Should we only return available fonts on the given device
553 15788 : if ( pOutDev )
554 : {
555 0 : pOutDev->ImplInitFontList();
556 :
557 : // Search Font in the FontList
558 0 : String aName;
559 0 : String aSearchName;
560 0 : xub_StrLen nIndex = 0;
561 0 : do
562 : {
563 0 : aSearchName = GetNextFontToken( aSearch, nIndex );
564 0 : GetEnglishSearchFontName( aSearchName );
565 0 : ImplDevFontListData* pFontFamily = pOutDev->mpFontList->ImplFindBySearchName( aSearchName );
566 0 : if( pFontFamily )
567 : {
568 0 : AddTokenFontName( aName, pFontFamily->GetFamilyName() );
569 0 : if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
570 0 : break;
571 : }
572 : }
573 : while ( nIndex != STRING_NOTFOUND );
574 0 : aFont.SetName( aName );
575 : }
576 :
577 : // No Name, than set all names
578 15788 : if ( !aFont.GetName().Len() )
579 : {
580 15788 : if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
581 : {
582 :
583 15737 : if( !pOutDev )
584 15737 : pOutDev = (const OutputDevice *)ImplGetSVData()->mpDefaultWin;
585 15737 : if( !pOutDev )
586 : {
587 203 : xub_StrLen nIndex = 0;
588 203 : aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
589 : }
590 : else
591 : {
592 15534 : pOutDev->ImplInitFontList();
593 :
594 15534 : aFont.SetName( aSearch );
595 :
596 : // convert to pixel height
597 15534 : Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
598 15534 : if ( !aSize.Height() )
599 : {
600 : // use default pixel height only when logical height is zero
601 0 : if ( aFont.GetHeight() )
602 0 : aSize.Height() = 1;
603 : else
604 0 : aSize.Height() = (12*pOutDev->mnDPIY)/72;
605 : }
606 :
607 : // use default width only when logical width is zero
608 15534 : if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
609 0 : aSize.Width() = 1;
610 :
611 : // get the name of the first available font
612 15534 : float fExactHeight = static_cast<float>(aSize.Height());
613 15534 : ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontList, aFont, aSize, fExactHeight, pOutDev->mpOutDevData ? &pOutDev->mpOutDevData->maDevFontSubst : NULL );
614 15534 : if (pEntry)
615 : {
616 15534 : if( pEntry->maFontSelData.mpFontData )
617 15534 : aFont.SetName( pEntry->maFontSelData.mpFontData->maName );
618 : else
619 0 : aFont.SetName( pEntry->maFontSelData.maTargetName );
620 : }
621 : }
622 : }
623 : else
624 51 : aFont.SetName( aSearch );
625 : }
626 : }
627 :
628 : #if OSL_DEBUG_LEVEL > 2
629 : const char* s = "DEFAULTFONT_SANS_UNKNOWN";
630 : switch ( nType )
631 : {
632 : case DEFAULTFONT_SANS_UNICODE: s = "DEFAULTFONT_SANS_UNICODE"; break;
633 : case DEFAULTFONT_UI_SANS: s = "DEFAULTFONT_UI_SANS"; break;
634 :
635 : case DEFAULTFONT_SANS: s = "DEFAULTFONT_SANS"; break;
636 : case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
637 : case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
638 : case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
639 :
640 : case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
641 : case DEFAULTFONT_LATIN_TEXT: s = "DEFAULTFONT_LATIN_TEXT"; break;
642 : case DEFAULTFONT_LATIN_PRESENTATION: s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
643 :
644 : case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
645 : case DEFAULTFONT_LATIN_FIXED: s = "DEFAULTFONT_LATIN_FIXED"; break;
646 : case DEFAULTFONT_UI_FIXED: s = "DEFAULTFONT_UI_FIXED"; break;
647 :
648 : case DEFAULTFONT_SYMBOL: s = "DEFAULTFONT_SYMBOL"; break;
649 :
650 : case DEFAULTFONT_CJK_TEXT: s = "DEFAULTFONT_CJK_TEXT"; break;
651 : case DEFAULTFONT_CJK_PRESENTATION: s = "DEFAULTFONT_CJK_PRESENTATION"; break;
652 : case DEFAULTFONT_CJK_SPREADSHEET: s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
653 : case DEFAULTFONT_CJK_HEADING: s = "DEFAULTFONT_CJK_HEADING"; break;
654 : case DEFAULTFONT_CJK_DISPLAY: s = "DEFAULTFONT_CJK_DISPLAY"; break;
655 :
656 : case DEFAULTFONT_CTL_TEXT: s = "DEFAULTFONT_CTL_TEXT"; break;
657 : case DEFAULTFONT_CTL_PRESENTATION: s = "DEFAULTFONT_CTL_PRESENTATION"; break;
658 : case DEFAULTFONT_CTL_SPREADSHEET: s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
659 : case DEFAULTFONT_CTL_HEADING: s = "DEFAULTFONT_CTL_HEADING"; break;
660 : case DEFAULTFONT_CTL_DISPLAY: s = "DEFAULTFONT_CTL_DISPLAY"; break;
661 : }
662 : fprintf( stderr, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
663 : s, eLang, nFlags,
664 : OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
665 : );
666 : #endif
667 :
668 15788 : return aFont;
669 : }
670 :
671 : // =======================================================================
672 :
673 0 : static unsigned ImplIsCJKFont( const String& rFontName )
674 : {
675 : // Test, if Fontname includes CJK characters --> In this case we
676 : // mention that it is a CJK font
677 0 : const sal_Unicode* pStr = rFontName.GetBuffer();
678 0 : while ( *pStr )
679 : {
680 : // japanese
681 0 : if ( ((*pStr >= 0x3040) && (*pStr <= 0x30FF)) ||
682 : ((*pStr >= 0x3190) && (*pStr <= 0x319F)) )
683 0 : return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
684 :
685 : // korean
686 0 : if ( ((*pStr >= 0xAC00) && (*pStr <= 0xD7AF)) ||
687 : ((*pStr >= 0x3130) && (*pStr <= 0x318F)) ||
688 : ((*pStr >= 0x1100) && (*pStr <= 0x11FF)) )
689 0 : return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
690 :
691 : // chinese
692 0 : if ( ((*pStr >= 0x3400) && (*pStr <= 0x9FFF)) )
693 0 : return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
694 :
695 : // cjk
696 0 : if ( ((*pStr >= 0x3000) && (*pStr <= 0xD7AF)) ||
697 : ((*pStr >= 0xFF00) && (*pStr <= 0xFFEE)) )
698 0 : return IMPL_FONT_ATTR_CJK;
699 :
700 0 : pStr++;
701 : }
702 :
703 0 : return 0;
704 : }
705 :
706 : // -----------------------------------------------------------------------
707 :
708 0 : static void ImplCalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth,
709 : FontFamily eFamily, const FontNameAttr* pFontAttr )
710 : {
711 0 : if ( eFamily != FAMILY_DONTKNOW )
712 : {
713 0 : if ( eFamily == FAMILY_SWISS )
714 0 : rType |= IMPL_FONT_ATTR_SANSSERIF;
715 0 : else if ( eFamily == FAMILY_ROMAN )
716 0 : rType |= IMPL_FONT_ATTR_SERIF;
717 0 : else if ( eFamily == FAMILY_SCRIPT )
718 0 : rType |= IMPL_FONT_ATTR_SCRIPT;
719 0 : else if ( eFamily == FAMILY_MODERN )
720 0 : rType |= IMPL_FONT_ATTR_FIXED;
721 0 : else if ( eFamily == FAMILY_DECORATIVE )
722 0 : rType |= IMPL_FONT_ATTR_DECORATIVE;
723 : }
724 :
725 0 : if ( pFontAttr )
726 : {
727 0 : rType |= pFontAttr->Type;
728 :
729 0 : if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
730 : (pFontAttr->Weight != WEIGHT_DONTKNOW) )
731 0 : rWeight = pFontAttr->Weight;
732 0 : if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
733 : (pFontAttr->Width != WIDTH_DONTKNOW) )
734 0 : rWidth = pFontAttr->Width;
735 : }
736 0 : }
737 :
738 : // =======================================================================
739 :
740 2622 : PhysicalFontFace::PhysicalFontFace( const ImplDevFontAttributes& rDFA, int nMagic )
741 : : ImplDevFontAttributes( rDFA ),
742 : mnWidth(0),
743 : mnHeight(0),
744 : mnMagic( nMagic ),
745 2622 : mpNext( NULL )
746 : {
747 : // StarSymbol is a unicode font, but it still deserves the symbol flag
748 2622 : if( !mbSymbolFlag )
749 5152 : if( 0 == GetFamilyName().CompareIgnoreCaseToAscii( "starsymbol", 10)
750 2576 : || 0 == GetFamilyName().CompareIgnoreCaseToAscii( "opensymbol", 10) )
751 0 : mbSymbolFlag = true;
752 2622 : }
753 :
754 : // -----------------------------------------------------------------------
755 :
756 62396 : StringCompare PhysicalFontFace::CompareIgnoreSize( const PhysicalFontFace& rOther ) const
757 : {
758 : // compare their width, weight, italic and style name
759 62396 : if( meWidthType < rOther.meWidthType )
760 0 : return COMPARE_LESS;
761 62396 : else if( meWidthType > rOther.meWidthType )
762 0 : return COMPARE_GREATER;
763 :
764 62396 : if( meWeight < rOther.meWeight )
765 396 : return COMPARE_LESS;
766 62000 : else if( meWeight > rOther.meWeight )
767 37068 : return COMPARE_GREATER;
768 :
769 24932 : if( meItalic < rOther.meItalic )
770 418 : return COMPARE_LESS;
771 24514 : else if( meItalic > rOther.meItalic )
772 24312 : return COMPARE_GREATER;
773 :
774 202 : StringCompare eCompare = maName.CompareTo( rOther.maName );
775 202 : return eCompare;
776 : }
777 :
778 : // -----------------------------------------------------------------------
779 :
780 42328 : StringCompare PhysicalFontFace::CompareWithSize( const PhysicalFontFace& rOther ) const
781 : {
782 42328 : StringCompare eCompare = CompareIgnoreSize( rOther );
783 42328 : if( eCompare != COMPARE_EQUAL )
784 42126 : return eCompare;
785 :
786 202 : if( mnHeight < rOther.mnHeight )
787 0 : return COMPARE_LESS;
788 202 : else if( mnHeight > rOther.mnHeight )
789 0 : return COMPARE_GREATER;
790 :
791 202 : if( mnWidth < rOther.mnWidth )
792 0 : return COMPARE_LESS;
793 202 : else if( mnWidth > rOther.mnWidth )
794 0 : return COMPARE_GREATER;
795 :
796 202 : return COMPARE_EQUAL;
797 : }
798 :
799 : // -----------------------------------------------------------------------
800 :
801 : struct FontMatchStatus
802 : {
803 : public:
804 : int mnFaceMatch;
805 : int mnHeightMatch;
806 : int mnWidthMatch;
807 : const sal_Unicode* mpTargetStyleName;
808 : };
809 :
810 5188 : bool PhysicalFontFace::IsBetterMatch( const FontSelectPattern& rFSD, FontMatchStatus& rStatus ) const
811 : {
812 5188 : int nMatch = 0;
813 :
814 5188 : const String& rFontName = rFSD.maTargetName;
815 5188 : if( (rFontName == maName) || rFontName.EqualsIgnoreCaseAscii( maName ) )
816 2484 : nMatch += 240000;
817 :
818 5188 : if( rStatus.mpTargetStyleName
819 0 : && maStyleName.EqualsIgnoreCaseAscii( rStatus.mpTargetStyleName ) )
820 0 : nMatch += 120000;
821 :
822 5188 : if( (rFSD.mePitch != PITCH_DONTKNOW) && (rFSD.mePitch == mePitch) )
823 1668 : nMatch += 20000;
824 :
825 : // prefer NORMAL font width
826 : // TODO: change when the upper layers can tell their width preference
827 5188 : if( meWidthType == WIDTH_NORMAL )
828 5168 : nMatch += 400;
829 20 : else if( (meWidthType == WIDTH_SEMI_EXPANDED) || (meWidthType == WIDTH_SEMI_CONDENSED) )
830 0 : nMatch += 300;
831 :
832 5188 : if( rFSD.meWeight != WEIGHT_DONTKNOW )
833 : {
834 : // if not bold or requiring emboldening prefer light fonts to bold fonts
835 5180 : FontWeight ePatternWeight = rFSD.mbEmbolden ? WEIGHT_NORMAL : rFSD.meWeight;
836 :
837 5180 : int nReqWeight = (int)ePatternWeight;
838 5180 : if ( ePatternWeight > WEIGHT_MEDIUM )
839 288 : nReqWeight += 100;
840 :
841 5180 : int nGivenWeight = (int)meWeight;
842 5180 : if( meWeight > WEIGHT_MEDIUM )
843 2590 : nGivenWeight += 100;
844 :
845 5180 : int nWeightDiff = nReqWeight - nGivenWeight;
846 :
847 5180 : if ( nWeightDiff == 0 )
848 2590 : nMatch += 1000;
849 2590 : else if ( nWeightDiff == +1 || nWeightDiff == -1 )
850 0 : nMatch += 700;
851 2590 : else if ( nWeightDiff < +50 && nWeightDiff > -50)
852 0 : nMatch += 200;
853 : }
854 : else // requested weight == WEIGHT_DONTKNOW
855 : {
856 : // prefer NORMAL font weight
857 : // TODO: change when the upper layers can tell their weight preference
858 8 : if( meWeight == WEIGHT_NORMAL )
859 4 : nMatch += 450;
860 4 : else if( meWeight == WEIGHT_MEDIUM )
861 0 : nMatch += 350;
862 4 : else if( (meWeight == WEIGHT_SEMILIGHT) || (meWeight == WEIGHT_SEMIBOLD) )
863 0 : nMatch += 200;
864 4 : else if( meWeight == WEIGHT_LIGHT )
865 0 : nMatch += 150;
866 : }
867 :
868 : // if requiring custom matrix to fake italic, prefer upright font
869 5188 : FontItalic ePatternItalic = rFSD.maItalicMatrix != ItalicMatrix() ? ITALIC_NONE : rFSD.meItalic;
870 :
871 5188 : if ( ePatternItalic == ITALIC_NONE )
872 : {
873 4656 : if( meItalic == ITALIC_NONE )
874 2328 : nMatch += 900;
875 : }
876 : else
877 : {
878 532 : if( ePatternItalic == meItalic )
879 266 : nMatch += 900;
880 266 : else if( meItalic != ITALIC_NONE )
881 0 : nMatch += 600;
882 : }
883 :
884 5188 : if( mbDevice )
885 0 : nMatch += 1;
886 :
887 5188 : int nHeightMatch = 0;
888 5188 : int nWidthMatch = 0;
889 :
890 5188 : if( IsScalable() )
891 : {
892 5188 : if( rFSD.mnOrientation != 0 )
893 28 : nMatch += 80;
894 5160 : else if( rFSD.mnWidth != 0 )
895 552 : nMatch += 25;
896 : else
897 4608 : nMatch += 5;
898 : }
899 : else
900 : {
901 0 : if( rFSD.mnHeight == mnHeight )
902 : {
903 0 : nMatch += 20;
904 0 : if( rFSD.mnWidth == mnWidth )
905 0 : nMatch += 10;
906 : }
907 : else
908 : {
909 : // for non-scalable fonts the size difference is very important
910 : // prefer the smaller font face because of clipping/overlapping issues
911 0 : int nHeightDiff = (rFSD.mnHeight - mnHeight) * 1000;
912 0 : nHeightMatch = (nHeightDiff >= 0) ? -nHeightDiff : 100+nHeightDiff;
913 0 : if( rFSD.mnHeight )
914 0 : nHeightMatch /= rFSD.mnHeight;
915 :
916 0 : if( (rFSD.mnWidth != 0) && (mnWidth != 0) && (rFSD.mnWidth != mnWidth) )
917 : {
918 0 : int nWidthDiff = (rFSD.mnWidth - mnWidth) * 100;
919 0 : nWidthMatch = (nWidthDiff >= 0) ? -nWidthDiff : +nWidthDiff;
920 : }
921 : }
922 : }
923 :
924 5188 : if( rStatus.mnFaceMatch > nMatch )
925 3680 : return false;
926 1508 : else if( rStatus.mnFaceMatch < nMatch )
927 : {
928 1508 : rStatus.mnFaceMatch = nMatch;
929 1508 : rStatus.mnHeightMatch = nHeightMatch;
930 1508 : rStatus.mnWidthMatch = nWidthMatch;
931 1508 : return true;
932 : }
933 :
934 : // when two fonts are still competing prefer the
935 : // one with the best matching height
936 0 : if( rStatus.mnHeightMatch > nHeightMatch )
937 0 : return false;
938 0 : else if( rStatus.mnHeightMatch < nHeightMatch )
939 : {
940 0 : rStatus.mnHeightMatch = nHeightMatch;
941 0 : rStatus.mnWidthMatch = nWidthMatch;
942 0 : return true;
943 : }
944 :
945 0 : if( rStatus.mnWidthMatch > nWidthMatch )
946 0 : return false;
947 :
948 0 : rStatus.mnWidthMatch = nWidthMatch;
949 0 : return true;
950 : }
951 :
952 : // =======================================================================
953 :
954 1865 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
955 : : maFontSelData( rFontSelData ),
956 : maMetric( rFontSelData ),
957 : mpConversion( NULL ),
958 : mnRefCount( 1 ),
959 : mnSetFontFlags( 0 ),
960 : mnOwnOrientation( 0 ),
961 : mnOrientation( 0 ),
962 : mbInit( false ),
963 1865 : mpUnicodeFallbackList( NULL )
964 : {
965 1865 : maFontSelData.mpFontEntry = this;
966 1865 : }
967 :
968 : // -----------------------------------------------------------------------
969 :
970 1804 : ImplFontEntry::~ImplFontEntry()
971 : {
972 902 : delete mpUnicodeFallbackList;
973 902 : }
974 :
975 : // -----------------------------------------------------------------------
976 :
977 4653 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
978 : {
979 : boost::hash<sal_UCS4> a;
980 : boost::hash<int > b;
981 4653 : return a(rData.first) ^ b(rData.second);
982 : }
983 :
984 453 : inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
985 : {
986 453 : if( !mpUnicodeFallbackList )
987 247 : mpUnicodeFallbackList = new UnicodeFallbackList;
988 453 : (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
989 453 : }
990 :
991 : // -----------------------------------------------------------------------
992 :
993 4694 : inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, String* pFontName ) const
994 : {
995 4694 : if( !mpUnicodeFallbackList )
996 494 : return false;
997 :
998 4200 : UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
999 4200 : if( it == mpUnicodeFallbackList->end() )
1000 1234 : return false;
1001 :
1002 2966 : *pFontName = (*it).second;
1003 2966 : return true;
1004 : }
1005 :
1006 : // -----------------------------------------------------------------------
1007 :
1008 0 : inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
1009 : {
1010 : // DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
1011 0 : UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
1012 : // DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
1013 0 : if( it == mpUnicodeFallbackList->end() )
1014 0 : return;
1015 0 : if( (*it).second == rFontName )
1016 0 : mpUnicodeFallbackList->erase( it );
1017 : }
1018 :
1019 : // =======================================================================
1020 :
1021 19708 : ImplDevFontListData::ImplDevFontListData( const String& rSearchName )
1022 : : mpFirst( NULL ),
1023 : maSearchName( rSearchName ),
1024 : mnTypeFaces( 0 ),
1025 : mnMatchType( 0 ),
1026 : meMatchWeight( WEIGHT_DONTKNOW ),
1027 : meMatchWidth( WIDTH_DONTKNOW ),
1028 : meFamily( FAMILY_DONTKNOW ),
1029 : mePitch( PITCH_DONTKNOW ),
1030 19708 : mnMinQuality( -1 )
1031 19708 : {}
1032 :
1033 : // -----------------------------------------------------------------------
1034 :
1035 17680 : ImplDevFontListData::~ImplDevFontListData()
1036 : {
1037 : // release all physical font faces
1038 36380 : while( mpFirst )
1039 : {
1040 18700 : PhysicalFontFace* pFace = mpFirst;
1041 18700 : mpFirst = pFace->GetNextFace();
1042 18700 : delete pFace;
1043 : }
1044 8840 : }
1045 :
1046 : // -----------------------------------------------------------------------
1047 :
1048 41892 : bool ImplDevFontListData::AddFontFace( PhysicalFontFace* pNewData )
1049 : {
1050 41892 : pNewData->mpNext = NULL;
1051 :
1052 41892 : if( !mpFirst )
1053 : {
1054 19708 : maName = pNewData->maName;
1055 19708 : maMapNames = pNewData->maMapNames;
1056 19708 : meFamily = pNewData->meFamily;
1057 19708 : mePitch = pNewData->mePitch;
1058 19708 : mnMinQuality = pNewData->mnQuality;
1059 : }
1060 : else
1061 : {
1062 22184 : if( meFamily == FAMILY_DONTKNOW )
1063 22184 : meFamily = pNewData->meFamily;
1064 22184 : if( mePitch == PITCH_DONTKNOW )
1065 0 : mePitch = pNewData->mePitch;
1066 22184 : if( mnMinQuality > pNewData->mnQuality )
1067 8504 : mnMinQuality = pNewData->mnQuality;
1068 : }
1069 :
1070 : // set attributes for attribute based font matching
1071 41892 : if( pNewData->IsScalable() )
1072 41892 : mnTypeFaces |= IMPL_DEVFONT_SCALABLE;
1073 :
1074 41892 : if( pNewData->IsSymbolFont() )
1075 760 : mnTypeFaces |= IMPL_DEVFONT_SYMBOL;
1076 : else
1077 41132 : mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL;
1078 :
1079 41892 : if( pNewData->meWeight != WEIGHT_DONTKNOW )
1080 : {
1081 41892 : if( pNewData->meWeight >= WEIGHT_SEMIBOLD )
1082 15626 : mnTypeFaces |= IMPL_DEVFONT_BOLD;
1083 26266 : else if( pNewData->meWeight <= WEIGHT_SEMILIGHT )
1084 2660 : mnTypeFaces |= IMPL_DEVFONT_LIGHT;
1085 : else
1086 23606 : mnTypeFaces |= IMPL_DEVFONT_NORMAL;
1087 : }
1088 :
1089 41892 : if( pNewData->meItalic == ITALIC_NONE )
1090 27786 : mnTypeFaces |= IMPL_DEVFONT_NONEITALIC;
1091 14106 : else if( (pNewData->meItalic == ITALIC_NORMAL)
1092 : || (pNewData->meItalic == ITALIC_OBLIQUE) )
1093 14106 : mnTypeFaces |= IMPL_DEVFONT_ITALIC;
1094 :
1095 41892 : if( (meMatchWeight == WEIGHT_DONTKNOW)
1096 : || (meMatchWidth == WIDTH_DONTKNOW)
1097 : || (mnMatchType == 0) )
1098 : {
1099 : // TODO: is it cheaper to calc matching attributes now or on demand?
1100 : // calc matching attributes if other entries are already initialized
1101 :
1102 : // MT: Perform05: Do lazy, quite expensive, not needed in start-up!
1103 : // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
1104 : // InitMatchData( rFontSubst, maSearchName );
1105 : // mbMatchData=true; // Somewhere else???
1106 : }
1107 :
1108 : // reassign name (sharing saves memory)
1109 41892 : if( pNewData->maName == maName )
1110 41892 : pNewData->maName = maName;
1111 :
1112 : // insert new physical font face into linked list
1113 : // TODO: get rid of linear search?
1114 : PhysicalFontFace* pData;
1115 41892 : PhysicalFontFace** ppHere = &mpFirst;
1116 166408 : for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
1117 : {
1118 42328 : StringCompare eComp = pNewData->CompareWithSize( *pData );
1119 42328 : if( eComp == COMPARE_GREATER )
1120 41312 : continue;
1121 1016 : if( eComp == COMPARE_LESS )
1122 814 : break;
1123 :
1124 : // ignore duplicate if its quality is worse
1125 202 : if( pNewData->mnQuality < pData->mnQuality )
1126 92 : return false;
1127 :
1128 : // keep the device font if its quality is good enough
1129 220 : if( (pNewData->mnQuality == pData->mnQuality)
1130 110 : && (pData->mbDevice || !pNewData->mbDevice) )
1131 110 : return false;
1132 :
1133 : // replace existing font face with a better one
1134 0 : pNewData->mpNext = pData->mpNext;
1135 0 : *ppHere = pNewData;
1136 0 : delete pData;
1137 0 : return true;
1138 : }
1139 :
1140 : // insert into or append to list of physical font faces
1141 41690 : pNewData->mpNext = pData;
1142 41690 : *ppHere = pNewData;
1143 41690 : return true;
1144 : }
1145 :
1146 : // -----------------------------------------------------------------------
1147 :
1148 : // get font attributes using the normalized font family name
1149 0 : void ImplDevFontListData::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
1150 : const String& rSearchName )
1151 : {
1152 0 : String aShortName;
1153 : // get font attributes from the decorated font name
1154 : rFontSubst.getMapName( rSearchName, aShortName, maMatchFamilyName,
1155 0 : meMatchWeight, meMatchWidth, mnMatchType );
1156 0 : const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
1157 : // eventually use the stripped name
1158 0 : if( !pFontAttr )
1159 0 : if( aShortName != rSearchName )
1160 0 : pFontAttr = rFontSubst.getSubstInfo( aShortName );
1161 0 : ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr );
1162 0 : mnMatchType |= ImplIsCJKFont( maName );
1163 0 : }
1164 :
1165 : // -----------------------------------------------------------------------
1166 :
1167 1865 : PhysicalFontFace* ImplDevFontListData::FindBestFontFace( const FontSelectPattern& rFSD ) const
1168 : {
1169 1865 : if( !mpFirst )
1170 0 : return NULL;
1171 1865 : if( !mpFirst->GetNextFace() )
1172 568 : return mpFirst;
1173 :
1174 : // FontName+StyleName should map to FamilyName+StyleName
1175 1297 : const String& rSearchName = rFSD.maTargetName;
1176 1297 : const sal_Unicode* pTargetStyleName = NULL;
1177 1890 : if( (rSearchName.Len() > maSearchName.Len())
1178 593 : && rSearchName.Equals( maSearchName, 0, maSearchName.Len() ) )
1179 0 : pTargetStyleName = rSearchName.GetBuffer() + maSearchName.Len() + 1;
1180 :
1181 : // linear search, TODO: improve?
1182 1297 : PhysicalFontFace* pFontFace = mpFirst;
1183 1297 : PhysicalFontFace* pBestFontFace = pFontFace;
1184 1297 : FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
1185 6485 : for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
1186 5188 : if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
1187 1508 : pBestFontFace = pFontFace;
1188 :
1189 1297 : return pBestFontFace;
1190 : }
1191 :
1192 : // -----------------------------------------------------------------------
1193 :
1194 : // update device font list with unique font faces, with uniqueness
1195 : // meaning different font attributes, but not different fonts sizes
1196 17992 : void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
1197 : {
1198 17992 : PhysicalFontFace* pPrevFace = NULL;
1199 56052 : for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1200 : {
1201 38060 : if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
1202 38060 : rDevFontList.Add( pFace );
1203 38060 : pPrevFace = pFace;
1204 : }
1205 17992 : }
1206 :
1207 : // -----------------------------------------------------------------------
1208 :
1209 0 : void ImplDevFontListData::GetFontHeights( std::set<int>& rHeights ) const
1210 : {
1211 : // add all available font heights
1212 0 : for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1213 0 : rHeights.insert( pFace->GetHeight() );
1214 0 : }
1215 :
1216 : // -----------------------------------------------------------------------
1217 :
1218 18564 : void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList& rDevFontList,
1219 : bool bScalable, bool bEmbeddable ) const
1220 : {
1221 57834 : for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1222 : {
1223 39270 : if( bScalable && !pFace->IsScalable() )
1224 0 : continue;
1225 39270 : if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
1226 0 : continue;
1227 :
1228 39270 : PhysicalFontFace* pClonedFace = pFace->Clone();
1229 39270 : rDevFontList.Add( pClonedFace );
1230 : }
1231 18564 : }
1232 :
1233 : // =======================================================================
1234 :
1235 394 : ImplDevFontList::ImplDevFontList()
1236 : : mbMatchData( false )
1237 : , mbMapNames( false )
1238 : , mpPreMatchHook( NULL )
1239 : , mpFallbackHook( NULL )
1240 : , mpFallbackList( NULL )
1241 394 : , mnFallbackCount( -1 )
1242 394 : {}
1243 :
1244 : // -----------------------------------------------------------------------
1245 :
1246 516 : ImplDevFontList::~ImplDevFontList()
1247 : {
1248 172 : Clear();
1249 344 : }
1250 :
1251 : // -----------------------------------------------------------------------
1252 :
1253 23 : void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
1254 : {
1255 23 : mpPreMatchHook = pHook;
1256 23 : }
1257 :
1258 : // -----------------------------------------------------------------------
1259 :
1260 23 : void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
1261 : {
1262 23 : mpFallbackHook = pHook;
1263 23 : }
1264 :
1265 : // -----------------------------------------------------------------------
1266 :
1267 344 : void ImplDevFontList::Clear()
1268 : {
1269 : // remove fallback lists
1270 344 : delete[] mpFallbackList;
1271 344 : mpFallbackList = NULL;
1272 344 : mnFallbackCount = -1;
1273 :
1274 : // clear all entries in the device font list
1275 344 : DevFontList::iterator it = maDevFontList.begin();
1276 9184 : for(; it != maDevFontList.end(); ++it )
1277 : {
1278 8840 : ImplDevFontListData* pEntry = (*it).second;
1279 8840 : delete pEntry;
1280 : }
1281 :
1282 344 : maDevFontList.clear();
1283 :
1284 : // match data must be recalculated too
1285 344 : mbMatchData = false;
1286 344 : }
1287 :
1288 :
1289 : // -----------------------------------------------------------------------
1290 :
1291 0 : void ImplDevFontList::InitGenericGlyphFallback( void ) const
1292 : {
1293 : // normalized family names of fonts suited for glyph fallback
1294 : // if a font is available related fonts can be ignored
1295 : // TODO: implement dynamic lists
1296 : static const char* aGlyphFallbackList[] = {
1297 : // empty strings separate the names of unrelated fonts
1298 : "eudc", "",
1299 : "arialunicodems", "cyberbit", "code2000", "",
1300 : "andalesansui", "",
1301 : "starsymbol", "opensymbol", "",
1302 : "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
1303 : "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
1304 : "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
1305 : "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
1306 : "shree", "mangal", "",
1307 : "raavi", "shruti", "tunga", "",
1308 : "latha", "gautami", "kartika", "vrinda", "",
1309 : "shayyalmt", "naskmt", "scheherazade", "",
1310 : "david", "nachlieli", "lucidagrande", "",
1311 : "norasi", "angsanaupc", "",
1312 : "khmerossystem", "",
1313 : "muktinarrow", "",
1314 : "phetsarathot", "",
1315 : "padauk", "pinlonmyanmar", "",
1316 : "iskoolapota", "lklug", "",
1317 : 0
1318 : };
1319 :
1320 0 : bool bHasEudc = false;
1321 0 : int nMaxLevel = 0;
1322 0 : int nBestQuality = 0;
1323 0 : ImplDevFontListData** pFallbackList = NULL;
1324 0 : for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
1325 : {
1326 : // advance to next sub-list when end-of-sublist marker
1327 0 : if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
1328 : {
1329 0 : if( nBestQuality > 0 )
1330 0 : if( ++nMaxLevel >= MAX_FALLBACK )
1331 : break;
1332 0 : if( !ppNames[1] )
1333 : break;
1334 0 : nBestQuality = 0;
1335 0 : continue;
1336 : }
1337 :
1338 : // test if the glyph fallback candidate font is available and scalable
1339 0 : String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 );
1340 0 : ImplDevFontListData* pFallbackFont = FindFontFamily( aTokenName );
1341 0 : if( !pFallbackFont )
1342 0 : continue;
1343 0 : if( !pFallbackFont->IsScalable() )
1344 0 : continue;
1345 :
1346 : // keep the best font of the glyph fallback sub-list
1347 0 : if( nBestQuality < pFallbackFont->GetMinQuality() )
1348 : {
1349 0 : nBestQuality = pFallbackFont->GetMinQuality();
1350 : // store available glyph fallback fonts
1351 0 : if( !pFallbackList )
1352 0 : pFallbackList = new ImplDevFontListData*[ MAX_FALLBACK ];
1353 0 : pFallbackList[ nMaxLevel ] = pFallbackFont;
1354 0 : if( !bHasEudc && !nMaxLevel )
1355 0 : bHasEudc = !strncmp( *ppNames, "eudc", 5 );
1356 : }
1357 0 : }
1358 :
1359 : #ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472#
1360 : // sort the list of fonts for glyph fallback by quality (highest first)
1361 : // #i33947# keep the EUDC font at the front of the list
1362 : // an insertion sort is good enough for this short list
1363 : const int nSortStart = bHasEudc ? 1 : 0;
1364 : for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
1365 : {
1366 : ImplDevFontListData* pTestFont = pFallbackList[ i ];
1367 : int nTestQuality = pTestFont->GetMinQuality();
1368 : for( j = i; --j >= nSortStart; )
1369 : if( nTestQuality > pFallbackList[j]->GetMinQuality() )
1370 : pFallbackList[ j+1 ] = pFallbackList[ j ];
1371 : else
1372 : break;
1373 : pFallbackList[ j+1 ] = pTestFont;
1374 : }
1375 : #endif
1376 :
1377 0 : mnFallbackCount = nMaxLevel;
1378 0 : mpFallbackList = pFallbackList;
1379 0 : }
1380 :
1381 : // -----------------------------------------------------------------------
1382 :
1383 3264 : ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
1384 : rtl::OUString& rMissingCodes, int nFallbackLevel ) const
1385 : {
1386 3264 : ImplDevFontListData* pFallbackData = NULL;
1387 :
1388 : // find a matching font candidate for platform specific glyph fallback
1389 3264 : if( mpFallbackHook )
1390 : {
1391 : // check cache for the first matching entry
1392 : // to avoid calling the expensive fallback hook (#i83491#)
1393 3264 : sal_UCS4 cChar = 0;
1394 3264 : bool bCached = true;
1395 3264 : sal_Int32 nStrIndex = 0;
1396 6528 : while( nStrIndex < rMissingCodes.getLength() )
1397 : {
1398 3264 : cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1399 3264 : bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
1400 : // ignore entries which don't have a fallback
1401 3264 : if( !bCached || (rFontSelData.maSearchName.Len() != 0) )
1402 3264 : break;
1403 : }
1404 :
1405 3264 : if( bCached )
1406 : {
1407 : // there is a matching fallback in the cache
1408 : // so update rMissingCodes with codepoints not yet resolved by this fallback
1409 1989 : int nRemainingLength = 0;
1410 1989 : sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
1411 1989 : String aFontName;
1412 4106 : while( nStrIndex < rMissingCodes.getLength() )
1413 : {
1414 128 : cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1415 128 : bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
1416 128 : if( !bCached || (rFontSelData.maSearchName != aFontName) )
1417 0 : pRemainingCodes[ nRemainingLength++ ] = cChar;
1418 : }
1419 1989 : rMissingCodes = rtl::OUString( pRemainingCodes, nRemainingLength );
1420 : }
1421 : else
1422 : {
1423 1275 : rtl::OUString aOldMissingCodes = rMissingCodes;
1424 : // call the hook to query the best matching glyph fallback font
1425 1275 : if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
1426 : // apply outdev3.cxx specific fontname normalization
1427 1275 : GetEnglishSearchFontName( rFontSelData.maSearchName );
1428 : else
1429 0 : rFontSelData.maSearchName = String();
1430 :
1431 : //See fdo#32665 for an example. FreeSerif that has glyphs in normal
1432 : //font, but not in the italic or bold version
1433 1275 : bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
1434 :
1435 : // cache the result even if there was no match, unless its from part of a font for which the properties need
1436 : // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
1437 : // for different input sizes, weights, etc. Basically the cache is way to naive
1438 1275 : if (!bSubSetOfFontRequiresPropertyFaking)
1439 : {
1440 27 : for(;;)
1441 : {
1442 1302 : if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
1443 453 : rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
1444 1302 : if( nStrIndex >= aOldMissingCodes.getLength() )
1445 1275 : break;
1446 27 : cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
1447 : }
1448 1275 : if( rFontSelData.maSearchName.Len() != 0 )
1449 : {
1450 : // remove cache entries that were still not resolved
1451 2550 : for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1452 : {
1453 0 : cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1454 0 : rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
1455 : }
1456 : }
1457 1275 : }
1458 : }
1459 :
1460 : // find the matching device font
1461 3264 : if( rFontSelData.maSearchName.Len() != 0 )
1462 3264 : pFallbackData = FindFontFamily( rFontSelData.maSearchName );
1463 : }
1464 :
1465 : // else find a matching font candidate for generic glyph fallback
1466 3264 : if( !pFallbackData )
1467 : {
1468 : // initialize font candidates for generic glyph fallback if needed
1469 0 : if( mnFallbackCount < 0 )
1470 0 : InitGenericGlyphFallback();
1471 : // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
1472 0 : if( nFallbackLevel < mnFallbackCount )
1473 0 : pFallbackData = mpFallbackList[ nFallbackLevel ];
1474 : }
1475 :
1476 3264 : return pFallbackData;
1477 : }
1478 :
1479 : // -----------------------------------------------------------------------
1480 :
1481 41892 : void ImplDevFontList::Add( PhysicalFontFace* pNewData )
1482 : {
1483 41892 : String aSearchName = pNewData->maName;
1484 41892 : GetEnglishSearchFontName( aSearchName );
1485 :
1486 41892 : DevFontList::const_iterator it = maDevFontList.find( aSearchName );
1487 41892 : ImplDevFontListData* pFoundData = NULL;
1488 41892 : if( it != maDevFontList.end() )
1489 22184 : pFoundData = (*it).second;
1490 :
1491 41892 : if( !pFoundData )
1492 : {
1493 19708 : pFoundData = new ImplDevFontListData( aSearchName );
1494 19708 : maDevFontList[ aSearchName ] = pFoundData;
1495 : }
1496 :
1497 41892 : bool bKeepNewData = pFoundData->AddFontFace( pNewData );
1498 :
1499 41892 : if( !bKeepNewData )
1500 202 : delete pNewData;
1501 41892 : }
1502 :
1503 : // -----------------------------------------------------------------------
1504 :
1505 : // find the font from the normalized font family name
1506 179193 : ImplDevFontListData* ImplDevFontList::ImplFindBySearchName( const String& rSearchName ) const
1507 : {
1508 : #ifdef DEBUG
1509 : String aTempName = rSearchName;
1510 : GetEnglishSearchFontName( aTempName );
1511 : DBG_ASSERT( aTempName == rSearchName, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
1512 : #endif
1513 :
1514 179193 : DevFontList::const_iterator it = maDevFontList.find( rSearchName );
1515 179193 : if( it == maDevFontList.end() )
1516 108851 : return NULL;
1517 :
1518 70342 : ImplDevFontListData* pFoundData = (*it).second;
1519 70342 : return pFoundData;
1520 : }
1521 :
1522 : // -----------------------------------------------------------------------
1523 :
1524 0 : ImplDevFontListData* ImplDevFontList::ImplFindByAliasName(const rtl::OUString& rSearchName,
1525 : const rtl::OUString& rShortName) const
1526 : {
1527 : // short circuit for impossible font name alias
1528 0 : if (rSearchName.isEmpty())
1529 0 : return NULL;
1530 :
1531 : // short circuit if no alias names are available
1532 0 : if (!mbMapNames)
1533 0 : return NULL;
1534 :
1535 : // use the font's alias names to find the font
1536 : // TODO: get rid of linear search
1537 0 : DevFontList::const_iterator it = maDevFontList.begin();
1538 0 : while( it != maDevFontList.end() )
1539 : {
1540 0 : ImplDevFontListData* pData = (*it).second;
1541 0 : if( !pData->maMapNames.Len() )
1542 0 : continue;
1543 :
1544 : // if one alias name matches we found a matching font
1545 0 : rtl::OUString aTempName;
1546 0 : xub_StrLen nIndex = 0;
1547 0 : do
1548 : {
1549 0 : aTempName = GetNextFontToken( pData->maMapNames, nIndex );
1550 : // Test, if the Font name match with one of the mapping names
1551 0 : if ( (aTempName == rSearchName) || (aTempName == rShortName) )
1552 0 : return pData;
1553 : }
1554 : while ( nIndex != STRING_NOTFOUND );
1555 0 : }
1556 :
1557 0 : return NULL;
1558 : }
1559 :
1560 : // -----------------------------------------------------------------------
1561 :
1562 6550 : ImplDevFontListData* ImplDevFontList::FindFontFamily( const String& rFontName ) const
1563 : {
1564 : // normalize the font fomily name and
1565 6550 : String aName = rFontName;
1566 6550 : GetEnglishSearchFontName( aName );
1567 6550 : ImplDevFontListData* pFound = ImplFindBySearchName( aName );
1568 6550 : return pFound;
1569 : }
1570 :
1571 : // -----------------------------------------------------------------------
1572 :
1573 0 : ImplDevFontListData* ImplDevFontList::ImplFindByTokenNames(const rtl::OUString& rTokenStr) const
1574 : {
1575 0 : ImplDevFontListData* pFoundData = NULL;
1576 :
1577 : // use normalized font name tokens to find the font
1578 0 : for( xub_StrLen nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
1579 : {
1580 0 : String aSearchName = GetNextFontToken( rTokenStr, nTokenPos );
1581 0 : if( !aSearchName.Len() )
1582 0 : continue;
1583 0 : GetEnglishSearchFontName( aSearchName );
1584 0 : pFoundData = ImplFindBySearchName( aSearchName );
1585 0 : if( pFoundData )
1586 : break;
1587 0 : }
1588 :
1589 0 : return pFoundData;
1590 : }
1591 :
1592 : // -----------------------------------------------------------------------
1593 :
1594 5934 : ImplDevFontListData* ImplDevFontList::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
1595 : {
1596 5934 : ImplDevFontListData* pFoundData = NULL;
1597 :
1598 : // use the font substitutions suggested by the FontNameAttr to find the font
1599 5934 : ::std::vector< String >::const_iterator it = rFontAttr.Substitutions.begin();
1600 53922 : for(; it != rFontAttr.Substitutions.end(); ++it )
1601 : {
1602 59856 : String aSearchName( *it );
1603 59856 : GetEnglishSearchFontName( aSearchName );
1604 :
1605 59856 : pFoundData = ImplFindBySearchName( aSearchName );
1606 59856 : if( pFoundData )
1607 5934 : return pFoundData;
1608 59856 : }
1609 :
1610 : // use known attributes from the configuration to find a matching substitute
1611 0 : const sal_uLong nSearchType = rFontAttr.Type;
1612 0 : if( nSearchType != 0 )
1613 : {
1614 0 : const FontWeight eSearchWeight = rFontAttr.Weight;
1615 0 : const FontWidth eSearchWidth = rFontAttr.Width;
1616 0 : const FontItalic eSearchSlant = ITALIC_DONTKNOW;
1617 0 : const String aSearchName;
1618 : pFoundData = ImplFindByAttributes( nSearchType,
1619 0 : eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
1620 0 : if( pFoundData )
1621 0 : return pFoundData;
1622 : }
1623 :
1624 0 : return NULL;
1625 : }
1626 :
1627 : // -----------------------------------------------------------------------
1628 :
1629 0 : void ImplDevFontList::InitMatchData() const
1630 : {
1631 : // short circuit if already done
1632 0 : if( mbMatchData )
1633 0 : return;
1634 0 : mbMatchData = true;
1635 :
1636 : // calculate MatchData for all entries
1637 0 : const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
1638 :
1639 0 : DevFontList::const_iterator it = maDevFontList.begin();
1640 0 : for(; it != maDevFontList.end(); ++it )
1641 : {
1642 0 : const String& rSearchName = (*it).first;
1643 0 : ImplDevFontListData* pEntry = (*it).second;
1644 :
1645 0 : pEntry->InitMatchData( rFontSubst, rSearchName );
1646 : }
1647 : }
1648 :
1649 : // -----------------------------------------------------------------------
1650 :
1651 0 : ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( sal_uLong nSearchType,
1652 : FontWeight eSearchWeight, FontWidth eSearchWidth,
1653 : FontItalic eSearchItalic, const rtl::OUString& rSearchFamilyName ) const
1654 : {
1655 0 : if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
1656 0 : nSearchType |= IMPL_FONT_ATTR_ITALIC;
1657 :
1658 : // don't bother to match attributes if the attributes aren't worth matching
1659 0 : if( !nSearchType
1660 : && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
1661 : && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
1662 0 : return NULL;
1663 :
1664 0 : InitMatchData();
1665 0 : ImplDevFontListData* pFoundData = NULL;
1666 :
1667 : long nTestMatch;
1668 0 : long nBestMatch = 40000;
1669 0 : sal_uLong nBestType = 0;
1670 :
1671 0 : DevFontList::const_iterator it = maDevFontList.begin();
1672 0 : for(; it != maDevFontList.end(); ++it )
1673 : {
1674 0 : ImplDevFontListData* pData = (*it).second;
1675 :
1676 : // Get all information about the matching font
1677 0 : sal_uLong nMatchType = pData->mnMatchType;
1678 0 : FontWeight eMatchWeight= pData->meMatchWeight;
1679 0 : FontWidth eMatchWidth = pData->meMatchWidth;
1680 :
1681 : // Calculate Match Value
1682 : // 1000000000
1683 : // 100000000
1684 : // 10000000 CJK, CTL, None-Latin, Symbol
1685 : // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
1686 : // Titling, Capitals, Outline, Shadow
1687 : // 100000 Match FamilyName, Serif, SansSerif, Italic,
1688 : // Width, Weight
1689 : // 10000 Scalable, Standard, Default,
1690 : // full, Normal, Knownfont,
1691 : // Otherstyle, +Special, +Decorative,
1692 : // 1000 Typewriter, Rounded, Gothic, Schollbook
1693 : // 100
1694 0 : nTestMatch = 0;
1695 :
1696 : // test CJK script attributes
1697 0 : if ( nSearchType & IMPL_FONT_ATTR_CJK )
1698 : {
1699 : // Matching language
1700 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
1701 0 : nTestMatch += 10000000*3;
1702 0 : if( nMatchType & IMPL_FONT_ATTR_CJK )
1703 0 : nTestMatch += 10000000*2;
1704 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1705 0 : nTestMatch += 10000000;
1706 : }
1707 0 : else if ( nMatchType & IMPL_FONT_ATTR_CJK )
1708 0 : nTestMatch -= 10000000;
1709 :
1710 : // test CTL script attributes
1711 0 : if( nSearchType & IMPL_FONT_ATTR_CTL )
1712 : {
1713 0 : if( nMatchType & IMPL_FONT_ATTR_CTL )
1714 0 : nTestMatch += 10000000*2;
1715 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1716 0 : nTestMatch += 10000000;
1717 : }
1718 0 : else if ( nMatchType & IMPL_FONT_ATTR_CTL )
1719 0 : nTestMatch -= 10000000;
1720 :
1721 : // test LATIN script attributes
1722 0 : if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
1723 : {
1724 0 : if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
1725 0 : nTestMatch += 10000000*2;
1726 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1727 0 : nTestMatch += 10000000;
1728 : }
1729 :
1730 : // test SYMBOL attributes
1731 0 : if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
1732 : {
1733 0 : const String& rSearchName = it->first;
1734 : // prefer some special known symbol fonts
1735 0 : if ( rSearchName.EqualsAscii( "starsymbol" ) )
1736 0 : nTestMatch += 10000000*6+(10000*3);
1737 0 : else if ( rSearchName.EqualsAscii( "opensymbol" ) )
1738 0 : nTestMatch += 10000000*6;
1739 0 : else if ( rSearchName.EqualsAscii( "starbats" )
1740 0 : || rSearchName.EqualsAscii( "wingdings" )
1741 0 : || rSearchName.EqualsAscii( "monotypesorts" )
1742 0 : || rSearchName.EqualsAscii( "dingbats" )
1743 0 : || rSearchName.EqualsAscii( "zapfdingbats" ) )
1744 0 : nTestMatch += 10000000*5;
1745 0 : else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL )
1746 0 : nTestMatch += 10000000*4;
1747 : else
1748 : {
1749 0 : if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
1750 0 : nTestMatch += 10000000*2;
1751 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1752 0 : nTestMatch += 10000000;
1753 : }
1754 : }
1755 0 : else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL )
1756 0 : nTestMatch -= 10000000;
1757 0 : else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
1758 0 : nTestMatch -= 10000;
1759 :
1760 : // match stripped family name
1761 0 : if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName.equals(pData->maMatchFamilyName)) )
1762 0 : nTestMatch += 1000000*3;
1763 :
1764 : // match ALLSCRIPT? attribute
1765 0 : if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
1766 : {
1767 0 : if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
1768 0 : nTestMatch += 1000000*2;
1769 0 : if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
1770 : {
1771 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
1772 0 : nTestMatch += 1000000*2;
1773 0 : if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
1774 0 : nTestMatch -= 1000000;
1775 : }
1776 : }
1777 0 : else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
1778 0 : nTestMatch -= 1000000;
1779 :
1780 : // test MONOSPACE+TYPEWRITER attributes
1781 0 : if( nSearchType & IMPL_FONT_ATTR_FIXED )
1782 : {
1783 0 : if( nMatchType & IMPL_FONT_ATTR_FIXED )
1784 0 : nTestMatch += 1000000*2;
1785 : // a typewriter attribute is even better
1786 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
1787 0 : nTestMatch += 10000*2;
1788 : }
1789 0 : else if( nMatchType & IMPL_FONT_ATTR_FIXED )
1790 0 : nTestMatch -= 1000000;
1791 :
1792 : // test SPECIAL attribute
1793 0 : if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
1794 : {
1795 0 : if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
1796 0 : nTestMatch += 10000;
1797 0 : else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
1798 : {
1799 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1800 0 : nTestMatch += 1000*2;
1801 0 : else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1802 0 : nTestMatch += 1000;
1803 : }
1804 : }
1805 0 : else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
1806 0 : nTestMatch -= 1000000;
1807 :
1808 : // test DECORATIVE attribute
1809 0 : if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
1810 : {
1811 0 : if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
1812 0 : nTestMatch += 10000;
1813 0 : else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
1814 : {
1815 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1816 0 : nTestMatch += 1000*2;
1817 0 : else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1818 0 : nTestMatch += 1000;
1819 : }
1820 : }
1821 0 : else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
1822 0 : nTestMatch -= 1000000;
1823 :
1824 : // test TITLE+CAPITALS attributes
1825 0 : if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1826 : {
1827 0 : if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1828 0 : nTestMatch += 1000000*2;
1829 0 : if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
1830 0 : nTestMatch += 1000000;
1831 0 : else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))
1832 : && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
1833 0 : nTestMatch += 1000000;
1834 : }
1835 0 : else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1836 0 : nTestMatch -= 1000000;
1837 :
1838 : // test OUTLINE+SHADOW attributes
1839 0 : if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1840 : {
1841 0 : if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1842 0 : nTestMatch += 1000000*2;
1843 0 : if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
1844 0 : nTestMatch += 1000000;
1845 0 : else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW))
1846 : && (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
1847 0 : nTestMatch += 1000000;
1848 : }
1849 0 : else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1850 0 : nTestMatch -= 1000000;
1851 :
1852 : // test font name substrings
1853 : // TODO: calculate name matching score using e.g. Levenstein distance
1854 0 : if( (rSearchFamilyName.getLength() >= 4) && (pData->maMatchFamilyName.Len() >= 4)
1855 0 : && ((rSearchFamilyName.indexOf( pData->maMatchFamilyName ) != -1)
1856 0 : || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
1857 0 : nTestMatch += 5000;
1858 :
1859 : // test SERIF attribute
1860 0 : if( nSearchType & IMPL_FONT_ATTR_SERIF )
1861 : {
1862 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1863 0 : nTestMatch += 1000000*2;
1864 0 : else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1865 0 : nTestMatch -= 1000000;
1866 : }
1867 :
1868 : // test SANSERIF attribute
1869 0 : if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
1870 : {
1871 0 : if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1872 0 : nTestMatch += 1000000;
1873 0 : else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
1874 0 : nTestMatch -= 1000000;
1875 : }
1876 :
1877 : // test ITALIC attribute
1878 0 : if( nSearchType & IMPL_FONT_ATTR_ITALIC )
1879 : {
1880 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC )
1881 0 : nTestMatch += 1000000*3;
1882 0 : if( nMatchType & IMPL_FONT_ATTR_ITALIC )
1883 0 : nTestMatch += 1000000;
1884 : }
1885 0 : else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT)
1886 : && ((nMatchType & IMPL_FONT_ATTR_ITALIC)
1887 0 : || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) )
1888 0 : nTestMatch -= 1000000*2;
1889 :
1890 : // test WIDTH attribute
1891 0 : if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
1892 : {
1893 0 : if( eSearchWidth < WIDTH_NORMAL )
1894 : {
1895 0 : if( eSearchWidth == eMatchWidth )
1896 0 : nTestMatch += 1000000*3;
1897 0 : else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
1898 0 : nTestMatch += 1000000;
1899 : }
1900 : else
1901 : {
1902 0 : if( eSearchWidth == eMatchWidth )
1903 0 : nTestMatch += 1000000*3;
1904 0 : else if( eMatchWidth > WIDTH_NORMAL )
1905 0 : nTestMatch += 1000000;
1906 : }
1907 : }
1908 0 : else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
1909 0 : nTestMatch -= 1000000;
1910 :
1911 : // test WEIGHT attribute
1912 0 : if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) )
1913 : {
1914 0 : if( eSearchWeight < WEIGHT_NORMAL )
1915 : {
1916 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT )
1917 0 : nTestMatch += 1000000;
1918 0 : if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
1919 0 : nTestMatch += 1000000;
1920 : }
1921 : else
1922 : {
1923 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD )
1924 0 : nTestMatch += 1000000;
1925 0 : if( eMatchWeight > WEIGHT_BOLD )
1926 0 : nTestMatch += 1000000;
1927 : }
1928 : }
1929 0 : else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM))
1930 0 : || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) )
1931 0 : nTestMatch -= 1000000;
1932 :
1933 : // prefer scalable fonts
1934 0 : if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE )
1935 0 : nTestMatch += 10000*4;
1936 : else
1937 0 : nTestMatch -= 10000*4;
1938 :
1939 : // test STANDARD+DEFAULT+FULL+NORMAL attributes
1940 0 : if( nMatchType & IMPL_FONT_ATTR_STANDARD )
1941 0 : nTestMatch += 10000*2;
1942 0 : if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
1943 0 : nTestMatch += 10000;
1944 0 : if( nMatchType & IMPL_FONT_ATTR_FULL )
1945 0 : nTestMatch += 10000;
1946 0 : if( nMatchType & IMPL_FONT_ATTR_NORMAL )
1947 0 : nTestMatch += 10000;
1948 :
1949 : // test OTHERSTYLE attribute
1950 0 : if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 )
1951 : {
1952 0 : nTestMatch -= 10000;
1953 : }
1954 :
1955 : // test ROUNDED attribute
1956 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
1957 0 : nTestMatch += 1000;
1958 :
1959 : // test TYPEWRITER attribute
1960 0 : if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
1961 0 : nTestMatch += 1000;
1962 :
1963 : // test GOTHIC attribute
1964 0 : if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
1965 : {
1966 0 : if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
1967 0 : nTestMatch += 1000*3;
1968 0 : if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1969 0 : nTestMatch += 1000*2;
1970 : }
1971 :
1972 : // test SCHOOLBOOK attribute
1973 0 : if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
1974 : {
1975 0 : if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
1976 0 : nTestMatch += 1000*3;
1977 0 : if( nMatchType & IMPL_FONT_ATTR_SERIF )
1978 0 : nTestMatch += 1000*2;
1979 : }
1980 :
1981 : // compare with best matching font yet
1982 0 : if ( nTestMatch > nBestMatch )
1983 : {
1984 0 : pFoundData = pData;
1985 0 : nBestMatch = nTestMatch;
1986 0 : nBestType = nMatchType;
1987 : }
1988 0 : else if( nTestMatch == nBestMatch )
1989 : {
1990 : // some fonts are more suitable defaults
1991 0 : if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
1992 : {
1993 0 : pFoundData = pData;
1994 0 : nBestType = nMatchType;
1995 : }
1996 0 : else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
1997 0 : !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
1998 : {
1999 0 : pFoundData = pData;
2000 0 : nBestType = nMatchType;
2001 : }
2002 : }
2003 : }
2004 :
2005 0 : return pFoundData;
2006 : }
2007 :
2008 : // -----------------------------------------------------------------------
2009 :
2010 0 : ImplDevFontListData* ImplDevFontList::FindDefaultFont() const
2011 : {
2012 : // try to find one of the default fonts of the
2013 : // UNICODE, SANSSERIF, SERIF or FIXED default font lists
2014 0 : const DefaultFontConfiguration& rDefaults = DefaultFontConfiguration::get();
2015 0 : com::sun::star::lang::Locale aLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2016 0 : String aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS_UNICODE );
2017 0 : ImplDevFontListData* pFoundData = ImplFindByTokenNames( aFontname );
2018 0 : if( pFoundData )
2019 0 : return pFoundData;
2020 :
2021 0 : aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS );
2022 0 : pFoundData = ImplFindByTokenNames( aFontname );
2023 0 : if( pFoundData )
2024 0 : return pFoundData;
2025 :
2026 0 : aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SERIF );
2027 0 : pFoundData = ImplFindByTokenNames( aFontname );
2028 0 : if( pFoundData )
2029 0 : return pFoundData;
2030 :
2031 0 : aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_FIXED );
2032 0 : pFoundData = ImplFindByTokenNames( aFontname );
2033 0 : if( pFoundData )
2034 0 : return pFoundData;
2035 :
2036 : // now try to find a reasonable non-symbol font
2037 :
2038 0 : InitMatchData();
2039 :
2040 0 : DevFontList::const_iterator it = maDevFontList.begin();
2041 0 : for(; it != maDevFontList.end(); ++it )
2042 : {
2043 0 : ImplDevFontListData* pData = (*it).second;
2044 0 : if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL )
2045 0 : continue;
2046 0 : pFoundData = pData;
2047 0 : if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
2048 0 : break;
2049 : }
2050 0 : if( pFoundData )
2051 0 : return pFoundData;
2052 :
2053 : // finding any font is better than finding no font at all
2054 0 : it = maDevFontList.begin();
2055 0 : if( it != maDevFontList.end() )
2056 0 : pFoundData = (*it).second;
2057 :
2058 0 : return pFoundData;
2059 : }
2060 :
2061 : // -----------------------------------------------------------------------
2062 :
2063 362 : ImplDevFontList* ImplDevFontList::Clone( bool bScalable, bool bEmbeddable ) const
2064 : {
2065 362 : ImplDevFontList* pClonedList = new ImplDevFontList;
2066 : // pClonedList->mbMatchData = mbMatchData;
2067 362 : pClonedList->mbMapNames = mbMapNames;
2068 362 : pClonedList->mpPreMatchHook = mpPreMatchHook;
2069 362 : pClonedList->mpFallbackHook = mpFallbackHook;
2070 :
2071 : // TODO: clone the config-font attributes too?
2072 362 : pClonedList->mbMatchData = false;
2073 :
2074 362 : DevFontList::const_iterator it = maDevFontList.begin();
2075 18926 : for(; it != maDevFontList.end(); ++it )
2076 : {
2077 18564 : const ImplDevFontListData* pFontFace = (*it).second;
2078 18564 : pFontFace->UpdateCloneFontList( *pClonedList, bScalable, bEmbeddable );
2079 : }
2080 :
2081 362 : return pClonedList;
2082 : }
2083 :
2084 : // -----------------------------------------------------------------------
2085 :
2086 350 : ImplGetDevFontList* ImplDevFontList::GetDevFontList() const
2087 : {
2088 350 : ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
2089 :
2090 350 : DevFontList::const_iterator it = maDevFontList.begin();
2091 18342 : for(; it != maDevFontList.end(); ++it )
2092 : {
2093 17992 : const ImplDevFontListData* pFontFamily = (*it).second;
2094 17992 : pFontFamily->UpdateDevFontList( *pGetDevFontList );
2095 : }
2096 :
2097 350 : return pGetDevFontList;
2098 : }
2099 :
2100 : // -----------------------------------------------------------------------
2101 :
2102 0 : ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) const
2103 : {
2104 0 : ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
2105 :
2106 0 : ImplDevFontListData* pFontFamily = FindFontFamily( rFontName );
2107 0 : if( pFontFamily != NULL )
2108 : {
2109 0 : std::set<int> rHeights;
2110 0 : pFontFamily->GetFontHeights( rHeights );
2111 :
2112 0 : std::set<int>::const_iterator it = rHeights.begin();
2113 0 : for(; it != rHeights.begin(); ++it )
2114 0 : pGetDevSizeList->Add( *it );
2115 : }
2116 :
2117 0 : return pGetDevSizeList;
2118 : }
2119 :
2120 63814 : FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont,
2121 : const String& rSearchName, const Size& rSize, float fExactHeight )
2122 : : maSearchName( rSearchName )
2123 63814 : , mnWidth( rSize.Width() )
2124 63814 : , mnHeight( rSize.Height() )
2125 : , mfExactHeight( fExactHeight)
2126 63814 : , mnOrientation( rFont.GetOrientation() )
2127 63814 : , meLanguage( rFont.GetLanguage() )
2128 63814 : , mbVertical( rFont.IsVertical() )
2129 : , mbNonAntialiased( false )
2130 382884 : , mbEmbolden( false )
2131 : {
2132 63814 : maTargetName = maName;
2133 :
2134 63814 : rFont.GetFontAttributes( *this );
2135 :
2136 : // normalize orientation between 0 and 3600
2137 63814 : if( 3600 <= (unsigned)mnOrientation )
2138 : {
2139 0 : if( mnOrientation >= 0 )
2140 0 : mnOrientation %= 3600;
2141 : else
2142 0 : mnOrientation = 3600 - (-mnOrientation % 3600);
2143 : }
2144 :
2145 : // normalize width and height
2146 63814 : if( mnHeight < 0 )
2147 0 : mnHeight = -mnHeight;
2148 63814 : if( mnWidth < 0 )
2149 150 : mnWidth = -mnWidth;
2150 63814 : }
2151 :
2152 63814 : FontSelectPattern::FontSelectPattern( const Font& rFont,
2153 : const String& rSearchName, const Size& rSize, float fExactHeight)
2154 : : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
2155 : , mpFontData( NULL )
2156 63814 : , mpFontEntry( NULL )
2157 : {
2158 63814 : }
2159 :
2160 : // NOTE: this ctor is still used on Windows. Do not remove.
2161 0 : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
2162 : const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
2163 : : ImplFontAttributes( rFontData )
2164 0 : , mnWidth( rSize.Width() )
2165 0 : , mnHeight( rSize.Height() )
2166 : , mfExactHeight( fExactHeight )
2167 : , mnOrientation( nOrientation )
2168 : , meLanguage( 0 )
2169 : , mbVertical( bVertical )
2170 : , mbNonAntialiased( false )
2171 0 : , mbEmbolden( false )
2172 : {
2173 0 : maTargetName = maSearchName = maName;
2174 : // NOTE: no normalization for width/height/orientation
2175 0 : }
2176 :
2177 0 : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
2178 : const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
2179 : : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
2180 : , mpFontData( &rFontData )
2181 0 : , mpFontEntry( NULL )
2182 : {
2183 0 : }
2184 :
2185 31264 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
2186 : {
2187 31264 : static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
2188 31264 : }
2189 :
2190 : // =======================================================================
2191 :
2192 136165 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
2193 : {
2194 136165 : return rFSD.hashCode();
2195 : }
2196 :
2197 136165 : size_t FontSelectPatternAttributes::hashCode() const
2198 : {
2199 : // TODO: does it pay off to improve this hash function?
2200 : static FontNameHash aFontNameHash;
2201 136165 : size_t nHash = aFontNameHash( maSearchName );
2202 : #ifdef ENABLE_GRAPHITE
2203 : // check for features and generate a unique hash if necessary
2204 136165 : if (maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2205 : != STRING_NOTFOUND)
2206 : {
2207 0 : nHash = aFontNameHash( maTargetName );
2208 : }
2209 : #endif
2210 136165 : nHash += 11 * mnHeight;
2211 136165 : nHash += 19 * meWeight;
2212 136165 : nHash += 29 * meItalic;
2213 136165 : nHash += 37 * mnOrientation;
2214 136165 : nHash += 41 * meLanguage;
2215 136165 : if( mbVertical )
2216 0 : nHash += 53;
2217 136165 : return nHash;
2218 : }
2219 :
2220 91037 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
2221 : {
2222 91037 : if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
2223 56498 : return false;
2224 :
2225 34539 : if (maTargetName != rOther.maTargetName)
2226 0 : return false;
2227 :
2228 34539 : if (maSearchName != rOther.maSearchName)
2229 0 : return false;
2230 :
2231 34539 : if (mnWidth != rOther.mnWidth)
2232 7 : return false;
2233 :
2234 34532 : if (mnHeight != rOther.mnHeight)
2235 2141 : return false;
2236 :
2237 32391 : if (mfExactHeight != rOther.mfExactHeight)
2238 55 : return false;
2239 :
2240 32336 : if (mnOrientation != rOther.mnOrientation)
2241 836 : return false;
2242 :
2243 31500 : if (meLanguage != rOther.meLanguage)
2244 236 : return false;
2245 :
2246 31264 : if (mbVertical != rOther.mbVertical)
2247 0 : return false;
2248 :
2249 31264 : if (mbNonAntialiased != rOther.mbNonAntialiased)
2250 0 : return false;
2251 :
2252 31264 : if (mbEmbolden != rOther.mbEmbolden)
2253 0 : return false;
2254 :
2255 31264 : if (maItalicMatrix != rOther.maItalicMatrix)
2256 0 : return false;
2257 :
2258 31264 : return true;
2259 : }
2260 :
2261 : // -----------------------------------------------------------------------
2262 :
2263 134544 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
2264 : {
2265 : // check normalized font family name
2266 134544 : if( rA.maSearchName != rB.maSearchName )
2267 66772 : return false;
2268 :
2269 : // check font transformation
2270 67772 : if( (rA.mnHeight != rB.mnHeight)
2271 : || (rA.mnWidth != rB.mnWidth)
2272 : || (rA.mnOrientation != rB.mnOrientation) )
2273 2182 : return false;
2274 :
2275 : // check mapping relevant attributes
2276 65590 : if( (rA.mbVertical != rB.mbVertical)
2277 : || (rA.meLanguage != rB.meLanguage) )
2278 0 : return false;
2279 :
2280 : // check font face attributes
2281 65590 : if( (rA.meWeight != rB.meWeight)
2282 : || (rA.meItalic != rB.meItalic)
2283 : // || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member
2284 : || (rA.mePitch != rB.mePitch) )
2285 374 : return false;
2286 :
2287 : // check style name
2288 65216 : if( rA.maStyleName != rB.maStyleName)
2289 3 : return false;
2290 :
2291 : // Symbol fonts may recode from one type to another So they are only
2292 : // safely equivalent for equal targets
2293 130475 : if (
2294 2998 : (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
2295 62264 : (rB.mpFontData && rB.mpFontData->IsSymbolFont())
2296 : )
2297 : {
2298 8372 : if (rA.maTargetName != rB.maTargetName)
2299 0 : return false;
2300 : }
2301 :
2302 : #ifdef ENABLE_GRAPHITE
2303 : // check for features
2304 130426 : if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2305 : != STRING_NOTFOUND ||
2306 65213 : rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2307 0 : != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
2308 0 : return false;
2309 : #endif
2310 :
2311 65213 : if (rA.mbEmbolden != rB.mbEmbolden)
2312 0 : return false;
2313 :
2314 65213 : if (rA.maItalicMatrix != rB.maItalicMatrix)
2315 0 : return false;
2316 :
2317 65213 : return true;
2318 : }
2319 :
2320 : // -----------------------------------------------------------------------
2321 :
2322 394 : ImplFontCache::ImplFontCache( bool bPrinter )
2323 : : mpFirstEntry( NULL ),
2324 : mnRef0Count( 0 ),
2325 394 : mbPrinter( bPrinter )
2326 394 : {}
2327 :
2328 : // -----------------------------------------------------------------------
2329 :
2330 344 : ImplFontCache::~ImplFontCache()
2331 : {
2332 172 : FontInstanceList::iterator it = maFontInstanceList.begin();
2333 624 : for(; it != maFontInstanceList.end(); ++it )
2334 : {
2335 452 : ImplFontEntry* pEntry = (*it).second;
2336 452 : delete pEntry;
2337 : }
2338 172 : }
2339 :
2340 : // -----------------------------------------------------------------------
2341 :
2342 63814 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
2343 : const Font& rFont, const Size& rSize, float fExactHeight, ImplDirectFontSubstitution* pDevSpecific )
2344 : {
2345 63814 : String aSearchName = rFont.GetName();
2346 :
2347 : // initialize internal font request object
2348 63814 : FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
2349 63814 : return GetFontEntry( pFontList, aFontSelData, pDevSpecific );
2350 : }
2351 :
2352 : // -----------------------------------------------------------------------
2353 :
2354 67078 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
2355 : FontSelectPattern& aFontSelData, ImplDirectFontSubstitution* pDevSpecific )
2356 : {
2357 : // check if a directly matching logical font instance is already cached,
2358 : // the most recently used font usually has a hit rate of >50%
2359 67078 : ImplFontEntry *pEntry = NULL;
2360 67078 : ImplDevFontListData* pFontFamily = NULL;
2361 : IFSD_Equal aIFSD_Equal;
2362 67078 : if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
2363 0 : pEntry = mpFirstEntry;
2364 : else
2365 : {
2366 67078 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2367 67078 : if( it != maFontInstanceList.end() )
2368 0 : pEntry = (*it).second;
2369 : }
2370 :
2371 67078 : if( !pEntry ) // no direct cache hit
2372 : {
2373 : // find the best matching logical font family and update font selector accordingly
2374 67078 : pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific );
2375 : DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
2376 67078 : if( pFontFamily )
2377 67078 : aFontSelData.maSearchName = pFontFamily->GetSearchName();
2378 :
2379 : // check if an indirectly matching logical font instance is already cached
2380 67078 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2381 67078 : if( it != maFontInstanceList.end() )
2382 : {
2383 : // we have an indirect cache hit
2384 65213 : pEntry = (*it).second;
2385 : }
2386 : }
2387 :
2388 67078 : PhysicalFontFace* pFontData = NULL;
2389 :
2390 67078 : if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
2391 : {
2392 1865 : bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
2393 1865 : pFontData = pFontFamily->FindBestFontFace( aFontSelData );
2394 1865 : aFontSelData.mpFontData = pFontData;
2395 1865 : bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
2396 :
2397 1865 : if (bNewIsSymbol != bOrigWasSymbol)
2398 : {
2399 : // it is possible, though generally unlikely, that at this point we
2400 : // will attempt to use a symbol font as a last-ditch fallback for a
2401 : // non-symbol font request or vice versa, and by changing
2402 : // aFontSelData.mpFontData to/from a symbol font we may now find
2403 : // something in the cache that can be reused which previously
2404 : // wasn't a candidate
2405 765 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2406 765 : if( it != maFontInstanceList.end() )
2407 0 : pEntry = (*it).second;
2408 : }
2409 : }
2410 :
2411 67078 : if( pEntry ) // cache hit => use existing font instance
2412 : {
2413 : // increase the font instance's reference count
2414 65213 : if( !pEntry->mnRefCount++ )
2415 18208 : --mnRef0Count;
2416 : }
2417 :
2418 67078 : if (!pEntry && pFontData)// still no cache hit => create a new font instance
2419 : {
2420 : // create a new logical font instance from this physical font face
2421 1865 : pEntry = pFontData->CreateFontInstance( aFontSelData );
2422 :
2423 : // if we found a different symbol font we need a symbol conversion table
2424 1865 : if( pFontData->IsSymbolFont() )
2425 : {
2426 511 : if( aFontSelData.maTargetName != aFontSelData.maSearchName )
2427 511 : pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
2428 : #ifdef MACOSX
2429 : //It might be better to dig out the font version of the target font
2430 : //to see if it's a modern re-coded apple symbol font in case that
2431 : //font shows up on a different platform
2432 : if (!pEntry->mpConversion &&
2433 : aFontSelData.maTargetName.EqualsIgnoreCaseAscii("symbol") &&
2434 : aFontSelData.maSearchName.EqualsIgnoreCaseAscii("symbol"))
2435 : {
2436 : pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") );
2437 : }
2438 : #endif
2439 : }
2440 :
2441 : // add the new entry to the cache
2442 1865 : maFontInstanceList[ aFontSelData ] = pEntry;
2443 : }
2444 :
2445 67078 : mpFirstEntry = pEntry;
2446 67078 : return pEntry;
2447 : }
2448 :
2449 : namespace
2450 : {
2451 39775 : rtl::OUString stripCharSetFromName(rtl::OUString aName)
2452 : {
2453 : //I worry that someone will have a font which *does* have
2454 : //e.g. "Greek" legitimately at the end of its name :-(
2455 : const char*suffixes[] =
2456 : {
2457 : " baltic",
2458 : " ce",
2459 : " cyr",
2460 : " greek",
2461 : " tur",
2462 : " (arabic)",
2463 : " (hebrew)",
2464 : " (thai)",
2465 : " (vietnamese)"
2466 39775 : };
2467 :
2468 : //These can be crazily piled up, e.g. Times New Roman CYR Greek
2469 39775 : bool bFinished = false;
2470 119325 : while (!bFinished)
2471 : {
2472 39775 : bFinished = true;
2473 397750 : for (size_t i = 0; i < SAL_N_ELEMENTS(suffixes); ++i)
2474 : {
2475 357975 : size_t nLen = strlen(suffixes[i]);
2476 357975 : if (aName.endsWithIgnoreAsciiCaseAsciiL(suffixes[i], nLen))
2477 : {
2478 0 : bFinished = false;
2479 0 : aName = aName.copy(0, aName.getLength() - nLen);
2480 : }
2481 : }
2482 : }
2483 39775 : return aName;
2484 : }
2485 : }
2486 :
2487 : // -----------------------------------------------------------------------
2488 :
2489 67078 : ImplDevFontListData* ImplDevFontList::ImplFindByFont( FontSelectPattern& rFSD,
2490 : bool bPrinter, ImplDirectFontSubstitution* pDevSpecific ) const
2491 : {
2492 : // give up if no fonts are available
2493 67078 : if( !Count() )
2494 0 : return NULL;
2495 :
2496 : // test if a font in the token list is available
2497 : // substitute the font if this was requested
2498 67078 : sal_uInt16 nSubstFlags = FONT_SUBSTITUTE_ALWAYS;
2499 67078 : if ( bPrinter )
2500 0 : nSubstFlags |= FONT_SUBSTITUTE_SCREENONLY;
2501 :
2502 67078 : bool bMultiToken = false;
2503 67078 : xub_StrLen nTokenPos = 0;
2504 67078 : String& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
2505 0 : for(;;)
2506 : {
2507 67078 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2508 67078 : aSearchName = rFSD.maTargetName;
2509 :
2510 : #ifdef ENABLE_GRAPHITE
2511 : // Until features are properly supported, they are appended to the
2512 : // font name, so we need to strip them off so the font is found.
2513 67078 : xub_StrLen nFeat = aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX);
2514 67078 : String aOrigName = rFSD.maTargetName;
2515 67078 : String aBaseFontName(aSearchName, 0, (nFeat != STRING_NOTFOUND)?nFeat:aSearchName.Len());
2516 67078 : if (nFeat != STRING_NOTFOUND && STRING_NOTFOUND !=
2517 0 : aSearchName.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
2518 : {
2519 0 : aSearchName = aBaseFontName;
2520 0 : rFSD.maTargetName = aBaseFontName;
2521 : }
2522 :
2523 : #endif
2524 :
2525 67078 : GetEnglishSearchFontName( aSearchName );
2526 67078 : ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
2527 : // #114999# special emboldening for Ricoh fonts
2528 : // TODO: smarter check for special cases by using PreMatch infrastructure?
2529 72838 : if( (rFSD.meWeight > WEIGHT_MEDIUM)
2530 5760 : && aSearchName.EqualsAscii( "hg", 0, 2) )
2531 : {
2532 0 : String aBoldName;
2533 0 : if( aSearchName.EqualsAscii( "hggothicb", 0, 9) )
2534 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hggothice"));
2535 0 : else if( aSearchName.EqualsAscii( "hgpgothicb", 0, 10) )
2536 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpgothice"));
2537 0 : else if( aSearchName.EqualsAscii( "hgminchol", 0, 9) )
2538 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchob"));
2539 0 : else if( aSearchName.EqualsAscii( "hgpminchol", 0, 10) )
2540 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchob"));
2541 0 : else if( aSearchName.EqualsAscii( "hgminchob" ) )
2542 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchoe"));
2543 0 : else if( aSearchName.EqualsAscii( "hgpminchob" ) )
2544 0 : aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchoe"));
2545 :
2546 0 : if( aBoldName.Len() && ImplFindBySearchName( aBoldName ) )
2547 : {
2548 : // the other font is available => use it
2549 0 : aSearchName = aBoldName;
2550 : // prevent synthetic emboldening of bold version
2551 0 : rFSD.meWeight = WEIGHT_DONTKNOW;
2552 0 : }
2553 : }
2554 :
2555 : #ifdef ENABLE_GRAPHITE
2556 : // restore the features to make the font selection data unique
2557 67078 : rFSD.maTargetName = aOrigName;
2558 : #endif
2559 : // check if the current font name token or its substitute is valid
2560 67078 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
2561 67078 : if( pFoundData )
2562 27303 : return pFoundData;
2563 :
2564 : // some systems provide special customization
2565 : // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
2566 : // because the system wants to map it to another font first, e.g. "Helvetica"
2567 : #ifdef ENABLE_GRAPHITE
2568 : // use the target name to search in the prematch hook
2569 39775 : rFSD.maTargetName = aBaseFontName;
2570 : #endif
2571 :
2572 : //Related: fdo#49271 RTF files often contain weird-ass
2573 : //Win 3.1/Win95 style fontnames which attempt to put the
2574 : //charset encoding into the filename
2575 : //http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
2576 39775 : rtl::OUString sStrippedName = stripCharSetFromName(rFSD.maTargetName);
2577 39775 : if (!sStrippedName.equals(rFSD.maTargetName))
2578 : {
2579 0 : rFSD.maTargetName = sStrippedName;
2580 0 : aSearchName = rFSD.maTargetName;
2581 0 : GetEnglishSearchFontName(aSearchName);
2582 0 : pFoundData = ImplFindBySearchName(aSearchName);
2583 0 : if( pFoundData )
2584 0 : return pFoundData;
2585 : }
2586 :
2587 39775 : if( mpPreMatchHook )
2588 : {
2589 39775 : if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
2590 33841 : GetEnglishSearchFontName( aSearchName );
2591 : }
2592 : #ifdef ENABLE_GRAPHITE
2593 : // the prematch hook uses the target name to search, but we now need
2594 : // to restore the features to make the font selection data unique
2595 39775 : rFSD.maTargetName = aOrigName;
2596 : #endif
2597 39775 : pFoundData = ImplFindBySearchName( aSearchName );
2598 39775 : if( pFoundData )
2599 33841 : return pFoundData;
2600 :
2601 : // break after last font name token was checked unsuccessfully
2602 5934 : if( nTokenPos == STRING_NOTFOUND)
2603 : break;
2604 0 : bMultiToken = true;
2605 39775 : }
2606 :
2607 : // if the first font was not available find the next available font in
2608 : // the semicolon separated list of font names. A font is also considered
2609 : // available when there is a matching entry in the Tools->Options->Fonts
2610 : // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
2611 : // font is available
2612 17802 : for( nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
2613 : {
2614 5934 : if( bMultiToken )
2615 : {
2616 0 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2617 0 : aSearchName = rFSD.maTargetName;
2618 0 : GetEnglishSearchFontName( aSearchName );
2619 : }
2620 : else
2621 5934 : nTokenPos = STRING_NOTFOUND;
2622 5934 : if( mpPreMatchHook )
2623 5934 : if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
2624 0 : GetEnglishSearchFontName( aSearchName );
2625 5934 : ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
2626 5934 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
2627 5934 : if( pFoundData )
2628 0 : return pFoundData;
2629 : }
2630 :
2631 : // if no font with a directly matching name is available use the
2632 : // first font name token and get its attributes to find a replacement
2633 5934 : if ( bMultiToken )
2634 : {
2635 0 : nTokenPos = 0;
2636 0 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2637 0 : aSearchName = rFSD.maTargetName;
2638 0 : GetEnglishSearchFontName( aSearchName );
2639 : }
2640 :
2641 5934 : String aSearchShortName;
2642 5934 : String aSearchFamilyName;
2643 5934 : FontWeight eSearchWeight = rFSD.meWeight;
2644 5934 : FontWidth eSearchWidth = rFSD.meWidthType;
2645 5934 : sal_uLong nSearchType = 0;
2646 : FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
2647 5934 : eSearchWeight, eSearchWidth, nSearchType );
2648 :
2649 : // note: the search name was already translated to english (if possible)
2650 :
2651 : // use the font's shortened name if needed
2652 5934 : if ( aSearchShortName != aSearchName )
2653 : {
2654 0 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchShortName );
2655 0 : if( pFoundData )
2656 : {
2657 : #ifdef UNX
2658 : /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
2659 : a korean bitmap font that is not suitable here. Use the font replacement table,
2660 : that automatically leads to the desired "HG Mincho Light J". Same story for
2661 : MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
2662 0 : static String aMS_Mincho( RTL_CONSTASCII_USTRINGPARAM("msmincho") );
2663 0 : static String aMS_Gothic( RTL_CONSTASCII_USTRINGPARAM("msgothic") );
2664 0 : if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
2665 : // TODO: add heuristic to only throw out the fake ms* fonts
2666 : #endif
2667 : {
2668 0 : return pFoundData;
2669 : }
2670 : }
2671 : }
2672 :
2673 : // use font fallback
2674 5934 : const FontNameAttr* pFontAttr = NULL;
2675 5934 : if( aSearchName.Len() )
2676 : {
2677 : // get fallback info using FontSubstConfiguration and
2678 : // the target name, it's shortened name and family name in that order
2679 5934 : const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
2680 5934 : pFontAttr = rFontSubst.getSubstInfo( aSearchName );
2681 5934 : if ( !pFontAttr && (aSearchShortName != aSearchName) )
2682 0 : pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
2683 5934 : if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
2684 0 : pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
2685 :
2686 : // try the font substitutions suggested by the fallback info
2687 5934 : if( pFontAttr )
2688 : {
2689 5934 : ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
2690 5934 : if( pFoundData )
2691 5934 : return pFoundData;
2692 : }
2693 : }
2694 :
2695 : // if a target symbol font is not available use a default symbol font
2696 0 : if( rFSD.IsSymbolFont() )
2697 : {
2698 0 : com::sun::star::lang::Locale aDefaultLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2699 0 : aSearchName = DefaultFontConfiguration::get().getDefaultFont( aDefaultLocale, DEFAULTFONT_SYMBOL );
2700 0 : ImplDevFontListData* pFoundData = ImplFindByTokenNames( aSearchName );
2701 0 : if( pFoundData )
2702 0 : return pFoundData;
2703 : }
2704 :
2705 : // now try the other font name tokens
2706 0 : while( nTokenPos != STRING_NOTFOUND )
2707 : {
2708 0 : rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2709 0 : if( !rFSD.maTargetName.Len() )
2710 0 : continue;
2711 :
2712 0 : aSearchName = rFSD.maTargetName;
2713 0 : GetEnglishSearchFontName( aSearchName );
2714 :
2715 0 : String aTempShortName;
2716 0 : String aTempFamilyName;
2717 0 : sal_uLong nTempType = 0;
2718 0 : FontWeight eTempWeight = rFSD.meWeight;
2719 0 : FontWidth eTempWidth = WIDTH_DONTKNOW;
2720 : FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
2721 0 : eTempWeight, eTempWidth, nTempType );
2722 :
2723 : // use a shortend token name if available
2724 0 : if( aTempShortName != aSearchName )
2725 : {
2726 0 : ImplDevFontListData* pFoundData = ImplFindBySearchName( aTempShortName );
2727 0 : if( pFoundData )
2728 0 : return pFoundData;
2729 : }
2730 :
2731 : // use a font name from font fallback list to determine font attributes
2732 :
2733 : // get fallback info using FontSubstConfiguration and
2734 : // the target name, it's shortened name and family name in that order
2735 0 : const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
2736 0 : const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
2737 0 : if ( !pTempFontAttr && (aTempShortName != aSearchName) )
2738 0 : pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
2739 0 : if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
2740 0 : pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
2741 :
2742 : // try the font substitutions suggested by the fallback info
2743 0 : if( pTempFontAttr )
2744 : {
2745 0 : ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
2746 0 : if( pFoundData )
2747 0 : return pFoundData;
2748 0 : if( !pFontAttr )
2749 0 : pFontAttr = pTempFontAttr;
2750 : }
2751 0 : }
2752 :
2753 : // if still needed use the alias names of the installed fonts
2754 0 : if( mbMapNames )
2755 : {
2756 0 : ImplDevFontListData* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
2757 0 : if( pFoundData )
2758 0 : return pFoundData;
2759 : }
2760 :
2761 : // if still needed use the font request's attributes to find a good match
2762 0 : if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
2763 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
2764 0 : else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
2765 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
2766 0 : else if (MsLangId::isKorean(rFSD.meLanguage))
2767 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
2768 0 : else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
2769 0 : nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
2770 : else
2771 : {
2772 0 : nSearchType |= ImplIsCJKFont( rFSD.maName );
2773 0 : if( rFSD.IsSymbolFont() )
2774 0 : nSearchType |= IMPL_FONT_ATTR_SYMBOL;
2775 : }
2776 :
2777 0 : ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.meFamily, pFontAttr );
2778 : ImplDevFontListData* pFoundData = ImplFindByAttributes( nSearchType,
2779 0 : eSearchWeight, eSearchWidth, rFSD.meItalic, aSearchFamilyName );
2780 :
2781 0 : if( pFoundData )
2782 : {
2783 : // overwrite font selection attributes using info from the typeface flags
2784 0 : if( (eSearchWeight >= WEIGHT_BOLD)
2785 : && (eSearchWeight > rFSD.meWeight)
2786 : && (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) )
2787 0 : rFSD.meWeight = eSearchWeight;
2788 0 : else if( (eSearchWeight < WEIGHT_NORMAL)
2789 : && (eSearchWeight < rFSD.meWeight)
2790 : && (eSearchWeight != WEIGHT_DONTKNOW)
2791 : && (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) )
2792 0 : rFSD.meWeight = eSearchWeight;
2793 :
2794 0 : if( (nSearchType & IMPL_FONT_ATTR_ITALIC)
2795 : && ((rFSD.meItalic == ITALIC_DONTKNOW) || (rFSD.meItalic == ITALIC_NONE))
2796 : && (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) )
2797 0 : rFSD.meItalic = ITALIC_NORMAL;
2798 : }
2799 : else
2800 : {
2801 : // if still needed fall back to default fonts
2802 0 : pFoundData = FindDefaultFont();
2803 : }
2804 :
2805 0 : return pFoundData;
2806 : }
2807 :
2808 : // -----------------------------------------------------------------------
2809 :
2810 3264 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList* pFontList,
2811 : FontSelectPattern& rFontSelData, int nFallbackLevel, rtl::OUString& rMissingCodes )
2812 : {
2813 : // get a candidate font for glyph fallback
2814 : // unless the previously selected font got a device specific substitution
2815 : // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
2816 3264 : if( nFallbackLevel >= 1)
2817 : {
2818 3264 : ImplDevFontListData* pFallbackData = NULL;
2819 :
2820 : //fdo#33898 If someone has EUDC installed then they really want that to
2821 : //be used as the first-choice glyph fallback seeing as it's filled with
2822 : //private area codes with don't make any sense in any other font so
2823 : //prioritise it here if it's available. Ideally we would remove from
2824 : //rMissingCodes all the glyphs which it is able to resolve as an
2825 : //optimization, but that's tricky to achieve cross-platform without
2826 : //sufficient heavy-weight code that's likely to undo the value of the
2827 : //optimization
2828 3264 : if (nFallbackLevel == 1)
2829 3264 : pFallbackData = pFontList->FindFontFamily(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EUDC")));
2830 3264 : if (!pFallbackData)
2831 3264 : pFallbackData = pFontList->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
2832 : // escape when there are no font candidates
2833 3264 : if( !pFallbackData )
2834 0 : return NULL;
2835 : // override the font name
2836 3264 : rFontSelData.maName = pFallbackData->GetFamilyName();
2837 : // clear the cached normalized name
2838 3264 : rFontSelData.maSearchName = String();
2839 : }
2840 :
2841 : // get device font without doing device specific substitutions
2842 3264 : ImplFontEntry* pFallbackFont = GetFontEntry( pFontList, rFontSelData, NULL );
2843 3264 : return pFallbackFont;
2844 : }
2845 :
2846 : // -----------------------------------------------------------------------
2847 :
2848 49719 : void ImplFontCache::Release( ImplFontEntry* pEntry )
2849 : {
2850 : static const int FONTCACHE_MAX = 50;
2851 :
2852 : DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
2853 49719 : if( --pEntry->mnRefCount > 0 )
2854 : return;
2855 :
2856 19668 : if( ++mnRef0Count < FONTCACHE_MAX )
2857 : return;
2858 :
2859 : // remove unused entries from font instance cache
2860 9 : FontInstanceList::iterator it_next = maFontInstanceList.begin();
2861 609 : while( it_next != maFontInstanceList.end() )
2862 : {
2863 591 : FontInstanceList::iterator it = it_next++;
2864 591 : ImplFontEntry* pFontEntry = (*it).second;
2865 591 : if( pFontEntry->mnRefCount > 0 )
2866 141 : continue;
2867 :
2868 450 : maFontInstanceList.erase( it );
2869 450 : delete pFontEntry;
2870 450 : --mnRef0Count;
2871 : DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
2872 :
2873 450 : if( mpFirstEntry == pFontEntry )
2874 3 : mpFirstEntry = NULL;
2875 : }
2876 :
2877 : DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
2878 : }
2879 :
2880 : // -----------------------------------------------------------------------
2881 :
2882 0 : void ImplFontCache::Invalidate()
2883 : {
2884 : // delete unreferenced entries
2885 0 : FontInstanceList::iterator it = maFontInstanceList.begin();
2886 0 : for(; it != maFontInstanceList.end(); ++it )
2887 : {
2888 0 : ImplFontEntry* pFontEntry = (*it).second;
2889 0 : if( pFontEntry->mnRefCount > 0 )
2890 0 : continue;
2891 :
2892 0 : delete pFontEntry;
2893 0 : --mnRef0Count;
2894 : }
2895 :
2896 : // #112304# make sure the font cache is really clean
2897 0 : mpFirstEntry = NULL;
2898 0 : maFontInstanceList.clear();
2899 :
2900 : DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
2901 0 : }
2902 :
2903 : // =======================================================================
2904 :
2905 0 : ImplMultiTextLineInfo::ImplMultiTextLineInfo()
2906 : {
2907 0 : mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
2908 0 : mnLines = 0;
2909 0 : mnSize = MULTITEXTLINEINFO_RESIZE;
2910 0 : }
2911 :
2912 :
2913 0 : ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
2914 : {
2915 0 : for ( xub_StrLen i = 0; i < mnLines; i++ )
2916 0 : delete mpLines[i];
2917 0 : delete [] mpLines;
2918 0 : }
2919 :
2920 0 : void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
2921 : {
2922 0 : if ( mnSize == mnLines )
2923 : {
2924 0 : mnSize += MULTITEXTLINEINFO_RESIZE;
2925 0 : PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
2926 0 : memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
2927 0 : mpLines = pNewLines;
2928 : }
2929 :
2930 0 : mpLines[mnLines] = pLine;
2931 0 : mnLines++;
2932 0 : }
2933 :
2934 0 : void ImplMultiTextLineInfo::Clear()
2935 : {
2936 0 : for ( xub_StrLen i = 0; i < mnLines; i++ )
2937 0 : delete mpLines[i];
2938 0 : mnLines = 0;
2939 0 : }
2940 :
2941 : // =======================================================================
2942 :
2943 0 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
2944 : {
2945 0 : FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
2946 :
2947 : // If no Position is set, then calculate the default position, which
2948 : // depends on the language
2949 0 : if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
2950 : {
2951 0 : LanguageType eLang = rFont.GetLanguage();
2952 : // In Chinese Simplified the EmphasisMarks are below/left
2953 0 : if (MsLangId::isSimplifiedChinese(eLang))
2954 0 : nEmphasisMark |= EMPHASISMARK_POS_BELOW;
2955 : else
2956 : {
2957 0 : eLang = rFont.GetCJKContextLanguage();
2958 : // In Chinese Simplified the EmphasisMarks are below/left
2959 0 : if (MsLangId::isSimplifiedChinese(eLang))
2960 0 : nEmphasisMark |= EMPHASISMARK_POS_BELOW;
2961 : else
2962 0 : nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
2963 : }
2964 : }
2965 :
2966 0 : return nEmphasisMark;
2967 : }
2968 :
2969 : // -----------------------------------------------------------------------
2970 :
2971 9 : sal_Bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
2972 : {
2973 9 : if ( !rFont.IsVertical() )
2974 9 : return sal_False;
2975 :
2976 0 : if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
2977 0 : || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
2978 : // the underline is right for Japanese only
2979 0 : return sal_True;
2980 :
2981 0 : return sal_False;
2982 : }
2983 :
2984 : // =======================================================================
2985 :
2986 113754 : void OutputDevice::ImplInitFontList() const
2987 : {
2988 113754 : if( ! mpFontList->Count() )
2989 : {
2990 21 : if( mpGraphics || ImplGetGraphics() )
2991 : {
2992 : RTL_LOGFILE_CONTEXT( aLog, "OutputDevice::ImplInitFontList()" );
2993 21 : mpGraphics->GetDevFontList( mpFontList );
2994 : }
2995 : }
2996 113754 : if( meOutDevType == OUTDEV_WINDOW && ! mpFontList->Count() )
2997 : {
2998 0 : String aError( RTL_CONSTASCII_USTRINGPARAM( "Application error: no fonts and no vcl resource found on your system" ) );
2999 0 : ResMgr* pMgr = ImplGetResMgr();
3000 0 : if( pMgr )
3001 : {
3002 0 : String aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
3003 0 : if( aResStr.Len() )
3004 0 : aError = aResStr;
3005 : }
3006 0 : Application::Abort( aError );
3007 : }
3008 113754 : }
3009 :
3010 : // =======================================================================
3011 :
3012 15354 : void OutputDevice::ImplInitFont() const
3013 : {
3014 : DBG_TESTSOLARMUTEX();
3015 :
3016 15354 : if (!mpFontEntry)
3017 15354 : return;
3018 :
3019 15354 : if ( mbInitFont )
3020 : {
3021 15354 : if ( meOutDevType != OUTDEV_PRINTER )
3022 : {
3023 : // decide if antialiasing is appropriate
3024 15251 : bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
3025 15251 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3026 15251 : bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
3027 15251 : bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
3028 15251 : mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
3029 : }
3030 :
3031 15354 : if( !mpPDFWriter || !mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
3032 : {
3033 : // select font in the device layers
3034 15354 : mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
3035 : }
3036 15354 : mbInitFont = false;
3037 : }
3038 : }
3039 :
3040 : // -----------------------------------------------------------------------
3041 :
3042 1330 : void OutputDevice::ImplInitTextColor()
3043 : {
3044 : DBG_TESTSOLARMUTEX();
3045 :
3046 1330 : if ( mbInitTextColor )
3047 : {
3048 1330 : mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
3049 1330 : mbInitTextColor = sal_False;
3050 : }
3051 1330 : }
3052 :
3053 : // -----------------------------------------------------------------------
3054 :
3055 76158 : bool OutputDevice::ImplNewFont() const
3056 : {
3057 : DBG_TESTSOLARMUTEX();
3058 :
3059 : // get correct font list on the PDF writer if necessary
3060 76158 : if( mpPDFWriter )
3061 : {
3062 0 : const ImplSVData* pSVData = ImplGetSVData();
3063 0 : if( mpFontList == pSVData->maGDIData.mpScreenFontList
3064 : || mpFontCache == pSVData->maGDIData.mpScreenFontCache )
3065 0 : const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
3066 : }
3067 :
3068 76158 : if ( !mbNewFont )
3069 27878 : return true;
3070 :
3071 : // we need a graphics
3072 48280 : if ( !mpGraphics && !ImplGetGraphics() )
3073 0 : return false;
3074 48280 : SalGraphics* pGraphics = mpGraphics;
3075 48280 : ImplInitFontList();
3076 :
3077 : // convert to pixel height
3078 : // TODO: replace integer based aSize completely with subpixel accurate type
3079 48280 : float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
3080 48280 : Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
3081 48280 : if ( !aSize.Height() )
3082 : {
3083 : // use default pixel height only when logical height is zero
3084 0 : if ( maFont.GetSize().Height() )
3085 0 : aSize.Height() = 1;
3086 : else
3087 0 : aSize.Height() = (12*mnDPIY)/72;
3088 0 : fExactHeight = static_cast<float>(aSize.Height());
3089 : }
3090 :
3091 : // select the default width only when logical width is zero
3092 48280 : if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
3093 50 : aSize.Width() = 1;
3094 :
3095 : // get font entry
3096 48280 : ImplDirectFontSubstitution* pDevSpecificSubst = NULL;
3097 48280 : if( mpOutDevData )
3098 1761 : pDevSpecificSubst = &mpOutDevData->maDevFontSubst;
3099 48280 : ImplFontEntry* pOldEntry = mpFontEntry;
3100 48280 : mpFontEntry = mpFontCache->GetFontEntry( mpFontList, maFont, aSize, fExactHeight, pDevSpecificSubst );
3101 48280 : if( pOldEntry )
3102 45269 : mpFontCache->Release( pOldEntry );
3103 :
3104 48280 : ImplFontEntry* pFontEntry = mpFontEntry;
3105 :
3106 48280 : if (!pFontEntry)
3107 0 : return false;
3108 :
3109 : // mark when lower layers need to get involved
3110 48280 : mbNewFont = sal_False;
3111 48280 : if( pFontEntry != pOldEntry )
3112 21859 : mbInitFont = sal_True;
3113 :
3114 : // select font when it has not been initialized yet
3115 48280 : if ( !pFontEntry->mbInit )
3116 : {
3117 1456 : ImplInitFont();
3118 :
3119 : // get metric data from device layers
3120 1456 : if ( pGraphics )
3121 : {
3122 1456 : pFontEntry->mbInit = true;
3123 :
3124 1456 : pFontEntry->maMetric.mnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
3125 1456 : if( mpPDFWriter && mpPDFWriter->isBuiltinFont( pFontEntry->maFontSelData.mpFontData ) )
3126 0 : mpPDFWriter->getFontMetric( &pFontEntry->maFontSelData, &(pFontEntry->maMetric) );
3127 : else
3128 1456 : pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
3129 :
3130 1456 : pFontEntry->maMetric.ImplInitTextLineSize( this );
3131 1456 : pFontEntry->maMetric.ImplInitAboveTextLineSize();
3132 :
3133 1456 : pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
3134 :
3135 1463 : if( pFontEntry->maFontSelData.mnOrientation
3136 7 : && !pFontEntry->maMetric.mnOrientation
3137 : && (meOutDevType != OUTDEV_PRINTER) )
3138 : {
3139 0 : pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
3140 0 : pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
3141 : }
3142 : else
3143 1456 : pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
3144 : }
3145 : }
3146 :
3147 : // enable kerning array if requested
3148 48280 : if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
3149 : {
3150 : // TODO: test if physical font supports kerning and disable if not
3151 3997 : if( pFontEntry->maMetric.mbKernableFont )
3152 643 : mbKerning = true;
3153 : }
3154 : else
3155 44283 : mbKerning = false;
3156 48280 : if ( maFont.GetKerning() & KERNING_ASIAN )
3157 0 : mbKerning = true;
3158 :
3159 : // calculate EmphasisArea
3160 48280 : mnEmphasisAscent = 0;
3161 48280 : mnEmphasisDescent = 0;
3162 48280 : if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
3163 : {
3164 0 : FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
3165 0 : long nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
3166 0 : if ( nEmphasisHeight < 1 )
3167 0 : nEmphasisHeight = 1;
3168 0 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
3169 0 : mnEmphasisDescent = nEmphasisHeight;
3170 : else
3171 0 : mnEmphasisAscent = nEmphasisHeight;
3172 : }
3173 :
3174 : // calculate text offset depending on TextAlignment
3175 48280 : TextAlign eAlign = maFont.GetAlign();
3176 48280 : if ( eAlign == ALIGN_BASELINE )
3177 : {
3178 37726 : mnTextOffX = 0;
3179 37726 : mnTextOffY = 0;
3180 : }
3181 10554 : else if ( eAlign == ALIGN_TOP )
3182 : {
3183 10079 : mnTextOffX = 0;
3184 10079 : mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
3185 10079 : if ( pFontEntry->mnOrientation )
3186 529 : ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
3187 : }
3188 : else // eAlign == ALIGN_BOTTOM
3189 : {
3190 475 : mnTextOffX = 0;
3191 475 : mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
3192 475 : if ( pFontEntry->mnOrientation )
3193 0 : ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
3194 : }
3195 :
3196 48398 : mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
3197 48162 : ((maFont.GetOverline() != UNDERLINE_NONE) && (maFont.GetOverline() != UNDERLINE_DONTKNOW)) ||
3198 96560 : ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
3199 96556 : mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() ||
3200 96556 : (maFont.GetRelief() != RELIEF_NONE);
3201 :
3202 : // #95414# fix for OLE objects which use scale factors very creatively
3203 48280 : if( mbMap && !aSize.Width() )
3204 : {
3205 41875 : int nOrigWidth = pFontEntry->maMetric.mnWidth;
3206 41875 : float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
3207 41875 : fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
3208 41875 : int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
3209 41875 : if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
3210 : {
3211 50 : Size aOrigSize = maFont.GetSize();
3212 50 : const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
3213 50 : mbMap = sal_False;
3214 50 : mbNewFont = sal_True;
3215 50 : ImplNewFont(); // recurse once using stretched width
3216 50 : mbMap = sal_True;
3217 50 : const_cast<Font&>(maFont).SetSize( aOrigSize );
3218 : }
3219 : }
3220 :
3221 48280 : return true;
3222 : }
3223 :
3224 : // -----------------------------------------------------------------------
3225 :
3226 12 : void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
3227 : long nDistX, long nDistY, long nWidth, long nHeight )
3228 : {
3229 12 : long nX = nDistX;
3230 12 : long nY = nDistY;
3231 :
3232 12 : short nOrientation = mpFontEntry->mnOrientation;
3233 12 : if ( nOrientation )
3234 : {
3235 : // Rotate rect without rounding problems for 90 degree rotations
3236 0 : if ( !(nOrientation % 900) )
3237 : {
3238 0 : if ( nOrientation == 900 )
3239 : {
3240 0 : long nTemp = nX;
3241 0 : nX = nY;
3242 0 : nY = -nTemp;
3243 0 : nTemp = nWidth;
3244 0 : nWidth = nHeight;
3245 0 : nHeight = nTemp;
3246 0 : nY -= nHeight;
3247 : }
3248 0 : else if ( nOrientation == 1800 )
3249 : {
3250 0 : nX = -nX;
3251 0 : nY = -nY;
3252 0 : nX -= nWidth;
3253 0 : nY -= nHeight;
3254 : }
3255 : else /* ( nOrientation == 2700 ) */
3256 : {
3257 0 : long nTemp = nX;
3258 0 : nX = -nY;
3259 0 : nY = nTemp;
3260 0 : nTemp = nWidth;
3261 0 : nWidth = nHeight;
3262 0 : nHeight = nTemp;
3263 0 : nX -= nWidth;
3264 : }
3265 : }
3266 : else
3267 : {
3268 0 : nX += nBaseX;
3269 0 : nY += nBaseY;
3270 : // inflate because polygons are drawn smaller
3271 0 : Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
3272 0 : Polygon aPoly( aRect );
3273 0 : aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
3274 0 : ImplDrawPolygon( aPoly );
3275 12 : return;
3276 : }
3277 : }
3278 :
3279 12 : nX += nBaseX;
3280 12 : nY += nBaseY;
3281 12 : mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
3282 : }
3283 :
3284 : // -----------------------------------------------------------------------
3285 :
3286 0 : void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
3287 : {
3288 0 : const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
3289 0 : const Point aBase = rSalLayout.DrawBase();
3290 0 : const long nX = aBase.X();
3291 0 : const long nY = aBase.Y();
3292 :
3293 0 : if ( mbLineColor || mbInitLineColor )
3294 : {
3295 0 : mpGraphics->SetLineColor();
3296 0 : mbInitLineColor = sal_True;
3297 : }
3298 0 : mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
3299 0 : mbInitFillColor = sal_True;
3300 :
3301 : ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
3302 : nWidth,
3303 0 : mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
3304 0 : }
3305 :
3306 : // -----------------------------------------------------------------------
3307 :
3308 0 : Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
3309 : {
3310 0 : Point aPoint = rSalLayout.GetDrawPosition();
3311 0 : long nX = aPoint.X();
3312 0 : long nY = aPoint.Y();
3313 :
3314 0 : long nWidth = rSalLayout.GetTextWidth();
3315 0 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
3316 :
3317 0 : nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
3318 :
3319 0 : if ( mpFontEntry->mnOrientation )
3320 : {
3321 0 : long nBaseX = nX, nBaseY = nY;
3322 0 : if ( !(mpFontEntry->mnOrientation % 900) )
3323 : {
3324 0 : long nX2 = nX+nWidth;
3325 0 : long nY2 = nY+nHeight;
3326 0 : ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
3327 0 : ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
3328 0 : nWidth = nX2-nX;
3329 0 : nHeight = nY2-nY;
3330 : }
3331 : else
3332 : {
3333 : // inflate by +1+1 because polygons are drawn smaller
3334 0 : Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
3335 0 : Polygon aPoly( aRect );
3336 0 : aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
3337 0 : return aPoly.GetBoundRect();
3338 : }
3339 : }
3340 :
3341 0 : return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
3342 : }
3343 :
3344 : // -----------------------------------------------------------------------
3345 :
3346 0 : void OutputDevice::ImplInitTextLineSize()
3347 : {
3348 0 : mpFontEntry->maMetric.ImplInitTextLineSize( this );
3349 0 : }
3350 :
3351 : // -----------------------------------------------------------------------
3352 :
3353 0 : void OutputDevice::ImplInitAboveTextLineSize()
3354 : {
3355 0 : mpFontEntry->maMetric.ImplInitAboveTextLineSize();
3356 0 : }
3357 :
3358 : // -----------------------------------------------------------------------
3359 :
3360 91037 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
3361 : {
3362 91037 : if (maName != rOther.maName)
3363 54506 : return false;
3364 :
3365 36531 : if (maStyleName != rOther.maStyleName)
3366 0 : return false;
3367 :
3368 36531 : if (meWeight != rOther.meWeight)
3369 850 : return false;
3370 :
3371 35681 : if (meItalic != rOther.meItalic)
3372 50 : return false;
3373 :
3374 35631 : if (meFamily != rOther.meFamily)
3375 1017 : return false;
3376 :
3377 34614 : if (mePitch != rOther.mePitch)
3378 75 : return false;
3379 :
3380 34539 : if (meWidthType != rOther.meWidthType)
3381 0 : return false;
3382 :
3383 34539 : if (mbSymbolFlag != rOther.mbSymbolFlag)
3384 0 : return false;
3385 :
3386 34539 : return true;
3387 : }
3388 :
3389 : // -----------------------------------------------------------------------
3390 :
3391 5129 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
3392 5129 : : ImplFontAttributes( rFontSelData )
3393 : {
3394 : // initialize the members provided by the font request
3395 5129 : mnWidth = rFontSelData.mnWidth;
3396 5129 : mnSlant = rFontSelData.GetSlant();
3397 5129 : mnOrientation = sal::static_int_cast<short>(rFontSelData.mnOrientation);
3398 :
3399 : // intialize the used font name
3400 5129 : if( rFontSelData.mpFontData )
3401 : {
3402 5129 : maName = rFontSelData.mpFontData->maName;
3403 5129 : maStyleName= rFontSelData.mpFontData->maStyleName;
3404 5129 : mbDevice = rFontSelData.mpFontData->mbDevice;
3405 5129 : mbKernableFont = true;
3406 : }
3407 : else
3408 : {
3409 0 : xub_StrLen nTokenPos = 0;
3410 0 : maName = GetNextFontToken( rFontSelData.maName, nTokenPos );
3411 0 : maStyleName= rFontSelData.maStyleName;
3412 0 : mbDevice = false;
3413 0 : mbKernableFont = false;
3414 : }
3415 :
3416 : // reset metrics that are usually measured for the font instance
3417 5129 : mnAscent = 0;
3418 5129 : mnDescent = 0;
3419 5129 : mnIntLeading = 0;
3420 5129 : mnExtLeading = 0;
3421 5129 : mnMinKashida = 0;
3422 :
3423 : // reset metrics that are usually derived from the measurements
3424 5129 : mnUnderlineSize = 0;
3425 5129 : mnUnderlineOffset = 0;
3426 5129 : mnBUnderlineSize = 0;
3427 5129 : mnBUnderlineOffset = 0;
3428 5129 : mnDUnderlineSize = 0;
3429 5129 : mnDUnderlineOffset1 = 0;
3430 5129 : mnDUnderlineOffset2 = 0;
3431 5129 : mnWUnderlineSize = 0;
3432 5129 : mnWUnderlineOffset = 0;
3433 5129 : mnAboveUnderlineSize = 0;
3434 5129 : mnAboveUnderlineOffset = 0;
3435 5129 : mnAboveBUnderlineSize = 0;
3436 5129 : mnAboveBUnderlineOffset = 0;
3437 5129 : mnAboveDUnderlineSize = 0;
3438 5129 : mnAboveDUnderlineOffset1 = 0;
3439 5129 : mnAboveDUnderlineOffset2 = 0;
3440 5129 : mnAboveWUnderlineSize = 0;
3441 5129 : mnAboveWUnderlineOffset = 0;
3442 5129 : mnStrikeoutSize = 0;
3443 5129 : mnStrikeoutOffset = 0;
3444 5129 : mnBStrikeoutSize = 0;
3445 5129 : mnBStrikeoutOffset = 0;
3446 5129 : mnDStrikeoutSize = 0;
3447 5129 : mnDStrikeoutOffset1 = 0;
3448 5129 : mnDStrikeoutOffset2 = 0;
3449 5129 : }
3450 :
3451 : // -----------------------------------------------------------------------
3452 :
3453 1456 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
3454 : {
3455 1456 : long nDescent = mnDescent;
3456 1456 : if ( nDescent <= 0 )
3457 : {
3458 0 : nDescent = mnAscent / 10;
3459 0 : if ( !nDescent )
3460 0 : nDescent = 1;
3461 : }
3462 :
3463 : // #i55341# for some fonts it is not a good idea to calculate
3464 : // their text line metrics from the real font descent
3465 : // => work around this problem just for these fonts
3466 1456 : if( 3*nDescent > mnAscent )
3467 8 : nDescent = mnAscent / 3;
3468 :
3469 1456 : long nLineHeight = ((nDescent*25)+50) / 100;
3470 1456 : if ( !nLineHeight )
3471 4 : nLineHeight = 1;
3472 1456 : long nLineHeight2 = nLineHeight / 2;
3473 1456 : if ( !nLineHeight2 )
3474 274 : nLineHeight2 = 1;
3475 :
3476 1456 : long nBLineHeight = ((nDescent*50)+50) / 100;
3477 1456 : if ( nBLineHeight == nLineHeight )
3478 42 : nBLineHeight++;
3479 1456 : long nBLineHeight2 = nBLineHeight/2;
3480 1456 : if ( !nBLineHeight2 )
3481 0 : nBLineHeight2 = 1;
3482 :
3483 1456 : long n2LineHeight = ((nDescent*16)+50) / 100;
3484 1456 : if ( !n2LineHeight )
3485 187 : n2LineHeight = 1;
3486 1456 : long n2LineDY = n2LineHeight;
3487 : /* #117909#
3488 : * add some pixels to minimum double line distance on higher resolution devices
3489 : */
3490 1456 : long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
3491 1456 : if ( n2LineDY < nMin2LineDY )
3492 841 : n2LineDY = nMin2LineDY;
3493 1456 : long n2LineDY2 = n2LineDY/2;
3494 1456 : if ( !n2LineDY2 )
3495 326 : n2LineDY2 = 1;
3496 :
3497 1456 : long nUnderlineOffset = mnDescent/2 + 1;
3498 1456 : long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
3499 :
3500 1456 : mnUnderlineSize = nLineHeight;
3501 1456 : mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
3502 :
3503 1456 : mnBUnderlineSize = nBLineHeight;
3504 1456 : mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
3505 :
3506 1456 : mnDUnderlineSize = n2LineHeight;
3507 1456 : mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
3508 1456 : mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
3509 :
3510 1456 : long nWCalcSize = mnDescent;
3511 1456 : if ( nWCalcSize < 6 )
3512 : {
3513 274 : if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
3514 42 : mnWUnderlineSize = nWCalcSize;
3515 : else
3516 232 : mnWUnderlineSize = 3;
3517 : }
3518 : else
3519 1182 : mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
3520 :
3521 : // #109280# the following line assures that wavelnes are never placed below the descent, however
3522 : // for most fonts the waveline then is drawn into the text, so we better keep the old solution
3523 : // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
3524 1456 : mnWUnderlineOffset = nUnderlineOffset;
3525 :
3526 1456 : mnStrikeoutSize = nLineHeight;
3527 1456 : mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
3528 :
3529 1456 : mnBStrikeoutSize = nBLineHeight;
3530 1456 : mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
3531 :
3532 1456 : mnDStrikeoutSize = n2LineHeight;
3533 1456 : mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
3534 1456 : mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
3535 1456 : }
3536 :
3537 : // -----------------------------------------------------------------------
3538 :
3539 1456 : void ImplFontMetricData::ImplInitAboveTextLineSize()
3540 : {
3541 1456 : long nIntLeading = mnIntLeading;
3542 : // TODO: assess usage of nLeading below (changed in extleading CWS)
3543 : // if no leading is available, we assume 15% of the ascent
3544 1456 : if ( nIntLeading <= 0 )
3545 : {
3546 16 : nIntLeading = mnAscent*15/100;
3547 16 : if ( !nIntLeading )
3548 0 : nIntLeading = 1;
3549 : }
3550 :
3551 1456 : long nLineHeight = ((nIntLeading*25)+50) / 100;
3552 1456 : if ( !nLineHeight )
3553 51 : nLineHeight = 1;
3554 :
3555 1456 : long nBLineHeight = ((nIntLeading*50)+50) / 100;
3556 1456 : if ( nBLineHeight == nLineHeight )
3557 208 : nBLineHeight++;
3558 :
3559 1456 : long n2LineHeight = ((nIntLeading*16)+50) / 100;
3560 1456 : if ( !n2LineHeight )
3561 229 : n2LineHeight = 1;
3562 :
3563 1456 : long nCeiling = -mnAscent;
3564 :
3565 1456 : mnAboveUnderlineSize = nLineHeight;
3566 1456 : mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
3567 :
3568 1456 : mnAboveBUnderlineSize = nBLineHeight;
3569 1456 : mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
3570 :
3571 1456 : mnAboveDUnderlineSize = n2LineHeight;
3572 1456 : mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
3573 1456 : mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2;
3574 :
3575 1456 : long nWCalcSize = nIntLeading;
3576 1456 : if ( nWCalcSize < 6 )
3577 : {
3578 317 : if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
3579 208 : mnAboveWUnderlineSize = nWCalcSize;
3580 : else
3581 109 : mnAboveWUnderlineSize = 3;
3582 : }
3583 : else
3584 1139 : mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
3585 :
3586 1456 : mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
3587 1456 : }
3588 :
3589 : // -----------------------------------------------------------------------
3590 :
3591 0 : static void ImplDrawWavePixel( long nOriginX, long nOriginY,
3592 : long nCurX, long nCurY,
3593 : short nOrientation,
3594 : SalGraphics* pGraphics,
3595 : OutputDevice* pOutDev,
3596 : sal_Bool bDrawPixAsRect,
3597 :
3598 : long nPixWidth, long nPixHeight )
3599 : {
3600 0 : if ( nOrientation )
3601 0 : ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
3602 :
3603 0 : if ( bDrawPixAsRect )
3604 : {
3605 :
3606 0 : pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
3607 : }
3608 : else
3609 : {
3610 0 : pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
3611 : }
3612 0 : }
3613 :
3614 : // -----------------------------------------------------------------------
3615 :
3616 0 : void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
3617 : long nDistX, long nDistY,
3618 : long nWidth, long nHeight,
3619 : long nLineWidth, short nOrientation,
3620 : const Color& rColor )
3621 : {
3622 0 : if ( !nHeight )
3623 0 : return;
3624 :
3625 0 : long nStartX = nBaseX + nDistX;
3626 0 : long nStartY = nBaseY + nDistY;
3627 :
3628 : // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
3629 0 : if ( (nLineWidth == 1) && (nHeight == 1) )
3630 : {
3631 0 : mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
3632 0 : mbInitLineColor = sal_True;
3633 :
3634 0 : long nEndX = nStartX+nWidth;
3635 0 : long nEndY = nStartY;
3636 0 : if ( nOrientation )
3637 : {
3638 0 : ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
3639 0 : ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
3640 : }
3641 0 : mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
3642 : }
3643 : else
3644 : {
3645 0 : long nCurX = nStartX;
3646 0 : long nCurY = nStartY;
3647 0 : long nDiffX = 2;
3648 0 : long nDiffY = nHeight-1;
3649 0 : long nCount = nWidth;
3650 0 : long nOffY = -1;
3651 : long nFreq;
3652 : long i;
3653 : long nPixWidth;
3654 : long nPixHeight;
3655 : sal_Bool bDrawPixAsRect;
3656 : // Auf Druckern die Pixel per DrawRect() ausgeben
3657 0 : if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
3658 : {
3659 0 : if ( mbLineColor || mbInitLineColor )
3660 : {
3661 0 : mpGraphics->SetLineColor();
3662 0 : mbInitLineColor = sal_True;
3663 : }
3664 0 : mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
3665 0 : mbInitFillColor = sal_True;
3666 0 : bDrawPixAsRect = sal_True;
3667 0 : nPixWidth = nLineWidth;
3668 0 : nPixHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
3669 : }
3670 : else
3671 : {
3672 0 : mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
3673 0 : mbInitLineColor = sal_True;
3674 0 : nPixWidth = 1;
3675 0 : nPixHeight = 1;
3676 0 : bDrawPixAsRect = sal_False;
3677 : }
3678 :
3679 0 : if ( !nDiffY )
3680 : {
3681 0 : while ( nWidth )
3682 : {
3683 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3684 : mpGraphics, this,
3685 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
3686 0 : nCurX++;
3687 0 : nWidth--;
3688 : }
3689 : }
3690 : else
3691 : {
3692 0 : nCurY += nDiffY;
3693 0 : nFreq = nCount / (nDiffX+nDiffY);
3694 0 : while ( nFreq-- )
3695 : {
3696 0 : for( i = nDiffY; i; --i )
3697 : {
3698 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3699 : mpGraphics, this,
3700 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
3701 0 : nCurX++;
3702 0 : nCurY += nOffY;
3703 : }
3704 0 : for( i = nDiffX; i; --i )
3705 : {
3706 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3707 : mpGraphics, this,
3708 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
3709 0 : nCurX++;
3710 : }
3711 0 : nOffY = -nOffY;
3712 : }
3713 0 : nFreq = nCount % (nDiffX+nDiffY);
3714 0 : if ( nFreq )
3715 : {
3716 0 : for( i = nDiffY; i && nFreq; --i, --nFreq )
3717 : {
3718 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3719 : mpGraphics, this,
3720 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
3721 0 : nCurX++;
3722 0 : nCurY += nOffY;
3723 :
3724 : }
3725 0 : for( i = nDiffX; i && nFreq; --i, --nFreq )
3726 : {
3727 : ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3728 : mpGraphics, this,
3729 0 : bDrawPixAsRect, nPixWidth, nPixHeight );
3730 0 : nCurX++;
3731 : }
3732 : }
3733 : }
3734 :
3735 : }
3736 : }
3737 :
3738 : // -----------------------------------------------------------------------
3739 :
3740 0 : void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
3741 : long nDistX, long nDistY, long nWidth,
3742 : FontUnderline eTextLine,
3743 : Color aColor,
3744 : sal_Bool bIsAbove )
3745 : {
3746 0 : ImplFontEntry* pFontEntry = mpFontEntry;
3747 : long nLineHeight;
3748 : long nLinePos;
3749 :
3750 0 : if ( bIsAbove )
3751 : {
3752 0 : nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
3753 0 : nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
3754 : }
3755 : else
3756 : {
3757 0 : nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
3758 0 : nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
3759 : }
3760 0 : if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
3761 0 : nLineHeight = 3;
3762 0 : long nLineWidth = (mnDPIX/300);
3763 0 : if ( !nLineWidth )
3764 0 : nLineWidth = 1;
3765 0 : if ( eTextLine == UNDERLINE_BOLDWAVE )
3766 0 : nLineWidth *= 2;
3767 0 : nLinePos += nDistY - (nLineHeight / 2);
3768 0 : long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
3769 0 : if ( eTextLine == UNDERLINE_DOUBLEWAVE )
3770 : {
3771 0 : long nOrgLineHeight = nLineHeight;
3772 0 : nLineHeight /= 3;
3773 0 : if ( nLineHeight < 2 )
3774 : {
3775 0 : if ( nOrgLineHeight > 1 )
3776 0 : nLineHeight = 2;
3777 : else
3778 0 : nLineHeight = 1;
3779 : }
3780 0 : long nLineDY = nOrgLineHeight-(nLineHeight*2);
3781 0 : if ( nLineDY < nLineWidthHeight )
3782 0 : nLineDY = nLineWidthHeight;
3783 0 : long nLineDY2 = nLineDY/2;
3784 0 : if ( !nLineDY2 )
3785 0 : nLineDY2 = 1;
3786 :
3787 0 : nLinePos -= nLineWidthHeight-nLineDY2;
3788 : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3789 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
3790 0 : nLinePos += nLineWidthHeight+nLineDY;
3791 : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3792 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
3793 : }
3794 : else
3795 : {
3796 0 : nLinePos -= nLineWidthHeight/2;
3797 : ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3798 0 : nLineWidth, mpFontEntry->mnOrientation, aColor );
3799 : }
3800 0 : }
3801 :
3802 : // -----------------------------------------------------------------------
3803 :
3804 18 : void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
3805 : long nDistX, long nDistY, long nWidth,
3806 : FontUnderline eTextLine,
3807 : Color aColor,
3808 : sal_Bool bIsAbove )
3809 : {
3810 18 : ImplFontEntry* pFontEntry = mpFontEntry;
3811 18 : long nLineHeight = 0;
3812 18 : long nLinePos = 0;
3813 18 : long nLinePos2 = 0;
3814 :
3815 18 : const long nY = nDistY;
3816 :
3817 18 : if ( eTextLine > UNDERLINE_LAST )
3818 0 : eTextLine = UNDERLINE_SINGLE;
3819 :
3820 18 : switch ( eTextLine )
3821 : {
3822 : case UNDERLINE_SINGLE:
3823 : case UNDERLINE_DOTTED:
3824 : case UNDERLINE_DASH:
3825 : case UNDERLINE_LONGDASH:
3826 : case UNDERLINE_DASHDOT:
3827 : case UNDERLINE_DASHDOTDOT:
3828 9 : if ( bIsAbove )
3829 : {
3830 0 : nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
3831 0 : nLinePos = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
3832 : }
3833 : else
3834 : {
3835 9 : nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
3836 9 : nLinePos = nY + pFontEntry->maMetric.mnUnderlineOffset;
3837 : }
3838 9 : break;
3839 : case UNDERLINE_BOLD:
3840 : case UNDERLINE_BOLDDOTTED:
3841 : case UNDERLINE_BOLDDASH:
3842 : case UNDERLINE_BOLDLONGDASH:
3843 : case UNDERLINE_BOLDDASHDOT:
3844 : case UNDERLINE_BOLDDASHDOTDOT:
3845 0 : if ( bIsAbove )
3846 : {
3847 0 : nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
3848 0 : nLinePos = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
3849 : }
3850 : else
3851 : {
3852 0 : nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
3853 0 : nLinePos = nY + pFontEntry->maMetric.mnBUnderlineOffset;
3854 : }
3855 0 : break;
3856 : case UNDERLINE_DOUBLE:
3857 0 : if ( bIsAbove )
3858 : {
3859 0 : nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
3860 0 : nLinePos = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
3861 0 : nLinePos2 = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
3862 : }
3863 : else
3864 : {
3865 0 : nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
3866 0 : nLinePos = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
3867 0 : nLinePos2 = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
3868 : }
3869 0 : break;
3870 : default:
3871 9 : break;
3872 : }
3873 :
3874 18 : if ( nLineHeight )
3875 : {
3876 9 : if ( mbLineColor || mbInitLineColor )
3877 : {
3878 9 : mpGraphics->SetLineColor();
3879 9 : mbInitLineColor = sal_True;
3880 : }
3881 9 : mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
3882 9 : mbInitFillColor = sal_True;
3883 :
3884 9 : long nLeft = nDistX;
3885 :
3886 9 : switch ( eTextLine )
3887 : {
3888 : case UNDERLINE_SINGLE:
3889 : case UNDERLINE_BOLD:
3890 9 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3891 9 : break;
3892 : case UNDERLINE_DOUBLE:
3893 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3894 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
3895 0 : break;
3896 : case UNDERLINE_DOTTED:
3897 : case UNDERLINE_BOLDDOTTED:
3898 : {
3899 0 : long nDotWidth = nLineHeight*mnDPIY;
3900 0 : nDotWidth += mnDPIY/2;
3901 0 : nDotWidth /= mnDPIY;
3902 0 : long nTempWidth = nDotWidth;
3903 0 : long nEnd = nLeft+nWidth;
3904 0 : while ( nLeft < nEnd )
3905 : {
3906 0 : if ( nLeft+nTempWidth > nEnd )
3907 0 : nTempWidth = nEnd-nLeft;
3908 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
3909 0 : nLeft += nDotWidth*2;
3910 : }
3911 : }
3912 0 : break;
3913 : case UNDERLINE_DASH:
3914 : case UNDERLINE_LONGDASH:
3915 : case UNDERLINE_BOLDDASH:
3916 : case UNDERLINE_BOLDLONGDASH:
3917 : {
3918 0 : long nDotWidth = nLineHeight*mnDPIY;
3919 0 : nDotWidth += mnDPIY/2;
3920 0 : nDotWidth /= mnDPIY;
3921 : long nMinDashWidth;
3922 : long nMinSpaceWidth;
3923 : long nSpaceWidth;
3924 : long nDashWidth;
3925 0 : if ( (eTextLine == UNDERLINE_LONGDASH) ||
3926 : (eTextLine == UNDERLINE_BOLDLONGDASH) )
3927 : {
3928 0 : nMinDashWidth = nDotWidth*6;
3929 0 : nMinSpaceWidth = nDotWidth*2;
3930 0 : nDashWidth = 200;
3931 0 : nSpaceWidth = 100;
3932 : }
3933 : else
3934 : {
3935 0 : nMinDashWidth = nDotWidth*4;
3936 0 : nMinSpaceWidth = (nDotWidth*150)/100;
3937 0 : nDashWidth = 100;
3938 0 : nSpaceWidth = 50;
3939 : }
3940 0 : nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
3941 0 : nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
3942 : // DashWidth wird gegebenenfalls verbreitert, wenn
3943 : // die dicke der Linie im Verhaeltnis zur Laenge
3944 : // zu dick wird
3945 0 : if ( nDashWidth < nMinDashWidth )
3946 0 : nDashWidth = nMinDashWidth;
3947 0 : if ( nSpaceWidth < nMinSpaceWidth )
3948 0 : nSpaceWidth = nMinSpaceWidth;
3949 0 : long nTempWidth = nDashWidth;
3950 0 : long nEnd = nLeft+nWidth;
3951 0 : while ( nLeft < nEnd )
3952 : {
3953 0 : if ( nLeft+nTempWidth > nEnd )
3954 0 : nTempWidth = nEnd-nLeft;
3955 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
3956 0 : nLeft += nDashWidth+nSpaceWidth;
3957 : }
3958 : }
3959 0 : break;
3960 : case UNDERLINE_DASHDOT:
3961 : case UNDERLINE_BOLDDASHDOT:
3962 : {
3963 0 : long nDotWidth = nLineHeight*mnDPIY;
3964 0 : nDotWidth += mnDPIY/2;
3965 0 : nDotWidth /= mnDPIY;
3966 0 : long nDashWidth = ((100*mnDPIX)+1270)/2540;
3967 0 : long nMinDashWidth = nDotWidth*4;
3968 : // DashWidth wird gegebenenfalls verbreitert, wenn
3969 : // die dicke der Linie im Verhaeltnis zur Laenge
3970 : // zu dick wird
3971 0 : if ( nDashWidth < nMinDashWidth )
3972 0 : nDashWidth = nMinDashWidth;
3973 0 : long nTempDotWidth = nDotWidth;
3974 0 : long nTempDashWidth = nDashWidth;
3975 0 : long nEnd = nLeft+nWidth;
3976 0 : while ( nLeft < nEnd )
3977 : {
3978 0 : if ( nLeft+nTempDotWidth > nEnd )
3979 0 : nTempDotWidth = nEnd-nLeft;
3980 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
3981 0 : nLeft += nDotWidth*2;
3982 0 : if ( nLeft > nEnd )
3983 0 : break;
3984 0 : if ( nLeft+nTempDashWidth > nEnd )
3985 0 : nTempDashWidth = nEnd-nLeft;
3986 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
3987 0 : nLeft += nDashWidth+nDotWidth;
3988 : }
3989 : }
3990 0 : break;
3991 : case UNDERLINE_DASHDOTDOT:
3992 : case UNDERLINE_BOLDDASHDOTDOT:
3993 : {
3994 0 : long nDotWidth = nLineHeight*mnDPIY;
3995 0 : nDotWidth += mnDPIY/2;
3996 0 : nDotWidth /= mnDPIY;
3997 0 : long nDashWidth = ((100*mnDPIX)+1270)/2540;
3998 0 : long nMinDashWidth = nDotWidth*4;
3999 : // DashWidth wird gegebenenfalls verbreitert, wenn
4000 : // die dicke der Linie im Verhaeltnis zur Laenge
4001 : // zu dick wird
4002 0 : if ( nDashWidth < nMinDashWidth )
4003 0 : nDashWidth = nMinDashWidth;
4004 0 : long nTempDotWidth = nDotWidth;
4005 0 : long nTempDashWidth = nDashWidth;
4006 0 : long nEnd = nLeft+nWidth;
4007 0 : while ( nLeft < nEnd )
4008 : {
4009 0 : if ( nLeft+nTempDotWidth > nEnd )
4010 0 : nTempDotWidth = nEnd-nLeft;
4011 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
4012 0 : nLeft += nDotWidth*2;
4013 0 : if ( nLeft > nEnd )
4014 0 : break;
4015 0 : if ( nLeft+nTempDotWidth > nEnd )
4016 0 : nTempDotWidth = nEnd-nLeft;
4017 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
4018 0 : nLeft += nDotWidth*2;
4019 0 : if ( nLeft > nEnd )
4020 0 : break;
4021 0 : if ( nLeft+nTempDashWidth > nEnd )
4022 0 : nTempDashWidth = nEnd-nLeft;
4023 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
4024 0 : nLeft += nDashWidth+nDotWidth;
4025 : }
4026 : }
4027 0 : break;
4028 : default:
4029 0 : break;
4030 : }
4031 : }
4032 18 : }
4033 :
4034 : // -----------------------------------------------------------------------
4035 :
4036 9 : void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
4037 : long nDistX, long nDistY, long nWidth,
4038 : FontStrikeout eStrikeout,
4039 : Color aColor )
4040 : {
4041 9 : ImplFontEntry* pFontEntry = mpFontEntry;
4042 9 : long nLineHeight = 0;
4043 9 : long nLinePos = 0;
4044 9 : long nLinePos2 = 0;
4045 :
4046 9 : long nY = nDistY;
4047 :
4048 9 : if ( eStrikeout > STRIKEOUT_LAST )
4049 0 : eStrikeout = STRIKEOUT_SINGLE;
4050 :
4051 9 : switch ( eStrikeout )
4052 : {
4053 : case STRIKEOUT_SINGLE:
4054 3 : nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
4055 3 : nLinePos = nY + pFontEntry->maMetric.mnStrikeoutOffset;
4056 3 : break;
4057 : case STRIKEOUT_BOLD:
4058 0 : nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
4059 0 : nLinePos = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
4060 0 : break;
4061 : case STRIKEOUT_DOUBLE:
4062 0 : nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
4063 0 : nLinePos = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
4064 0 : nLinePos2 = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
4065 0 : break;
4066 : default:
4067 6 : break;
4068 : }
4069 :
4070 9 : if ( nLineHeight )
4071 : {
4072 3 : if ( mbLineColor || mbInitLineColor )
4073 : {
4074 3 : mpGraphics->SetLineColor();
4075 3 : mbInitLineColor = sal_True;
4076 : }
4077 3 : mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
4078 3 : mbInitFillColor = sal_True;
4079 :
4080 3 : const long& nLeft = nDistX;
4081 :
4082 3 : switch ( eStrikeout )
4083 : {
4084 : case STRIKEOUT_SINGLE:
4085 : case STRIKEOUT_BOLD:
4086 3 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
4087 3 : break;
4088 : case STRIKEOUT_DOUBLE:
4089 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
4090 0 : ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
4091 0 : break;
4092 : default:
4093 0 : break;
4094 : }
4095 : }
4096 9 : }
4097 :
4098 : // -----------------------------------------------------------------------
4099 :
4100 0 : void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
4101 : long nDistX, long nDistY, long nWidth,
4102 : FontStrikeout eStrikeout,
4103 : Color aColor )
4104 : {
4105 : //See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
4106 : //to tweak this
4107 0 : if (!nWidth)
4108 : return;
4109 :
4110 : // PDF-export does its own strikeout drawing... why again?
4111 0 : if( mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) )
4112 : return;
4113 :
4114 : // prepare string for strikeout measurement
4115 : static char cStrikeoutChar;
4116 0 : if ( eStrikeout == STRIKEOUT_SLASH )
4117 0 : cStrikeoutChar = '/';
4118 : else // ( eStrikeout == STRIKEOUT_X )
4119 0 : cStrikeoutChar = 'X';
4120 : static const int nTestStrLen = 4;
4121 : static const int nMaxStrikeStrLen = 2048;
4122 : sal_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
4123 0 : for( int i = 0; i < nTestStrLen; ++i)
4124 0 : aChars[i] = cStrikeoutChar;
4125 0 : const rtl::OUString aStrikeoutTest(aChars, nTestStrLen);
4126 :
4127 : // calculate approximation of strikeout atom size
4128 0 : long nStrikeoutWidth = 0;
4129 0 : SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
4130 0 : if( pLayout )
4131 : {
4132 0 : nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
4133 0 : pLayout->Release();
4134 : }
4135 0 : if( nStrikeoutWidth <= 0 ) // sanity check
4136 : return;
4137 :
4138 0 : int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
4139 0 : if( nStrikeStrLen > nMaxStrikeStrLen )
4140 0 : nStrikeStrLen = nMaxStrikeStrLen;
4141 :
4142 : // build the strikeout string
4143 0 : for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
4144 0 : aChars[i] = cStrikeoutChar;
4145 0 : const rtl::OUString aStrikeoutText(aChars, nStrikeStrLen);
4146 :
4147 0 : if( mpFontEntry->mnOrientation )
4148 0 : ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
4149 0 : nBaseX += nDistX;
4150 0 : nBaseY += nDistY;
4151 :
4152 : // strikeout text has to be left aligned
4153 0 : sal_uLong nOrigTLM = mnTextLayoutMode;
4154 0 : mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
4155 0 : pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN );
4156 0 : mnTextLayoutMode = nOrigTLM;
4157 :
4158 0 : if( !pLayout )
4159 : return;
4160 :
4161 : // draw the strikeout text
4162 0 : const Color aOldColor = GetTextColor();
4163 0 : SetTextColor( aColor );
4164 0 : ImplInitTextColor();
4165 :
4166 0 : pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
4167 :
4168 0 : Rectangle aPixelRect;
4169 0 : aPixelRect.Left() = nBaseX+mnTextOffX;
4170 0 : aPixelRect.Right() = aPixelRect.Left()+nWidth;
4171 0 : aPixelRect.Bottom() = nBaseY+mpFontEntry->maMetric.mnDescent;
4172 0 : aPixelRect.Top() = nBaseY-mpFontEntry->maMetric.mnAscent;
4173 :
4174 0 : if (mpFontEntry->mnOrientation)
4175 : {
4176 0 : Polygon aPoly( aPixelRect );
4177 0 : aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
4178 0 : aPixelRect = aPoly.GetBoundRect();
4179 : }
4180 :
4181 0 : Push( PUSH_CLIPREGION );
4182 0 : IntersectClipRegion( PixelToLogic(aPixelRect) );
4183 0 : if( mbInitClipRegion )
4184 0 : ImplInitClipRegion();
4185 :
4186 0 : pLayout->DrawText( *mpGraphics );
4187 :
4188 0 : pLayout->Release();
4189 0 : Pop();
4190 :
4191 0 : SetTextColor( aOldColor );
4192 0 : ImplInitTextColor();
4193 : }
4194 :
4195 : // -----------------------------------------------------------------------
4196 :
4197 9 : void OutputDevice::ImplDrawTextLine( long nX, long nY,
4198 : long nDistX, long nWidth,
4199 : FontStrikeout eStrikeout,
4200 : FontUnderline eUnderline,
4201 : FontUnderline eOverline,
4202 : sal_Bool bUnderlineAbove )
4203 : {
4204 9 : if ( !nWidth )
4205 9 : return;
4206 :
4207 9 : Color aStrikeoutColor = GetTextColor();
4208 9 : Color aUnderlineColor = GetTextLineColor();
4209 9 : Color aOverlineColor = GetOverlineColor();
4210 9 : sal_Bool bStrikeoutDone = sal_False;
4211 9 : sal_Bool bUnderlineDone = sal_False;
4212 9 : sal_Bool bOverlineDone = sal_False;
4213 :
4214 9 : if ( IsRTLEnabled() )
4215 : {
4216 : // --- RTL --- mirror at basex
4217 0 : long nXAdd = nWidth - nDistX;
4218 0 : if( mpFontEntry->mnOrientation )
4219 0 : nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
4220 0 : nX += nXAdd - 1;
4221 : }
4222 :
4223 9 : if ( !IsTextLineColor() )
4224 9 : aUnderlineColor = GetTextColor();
4225 :
4226 9 : if ( !IsOverlineColor() )
4227 9 : aOverlineColor = GetTextColor();
4228 :
4229 9 : if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
4230 : (eUnderline == UNDERLINE_WAVE) ||
4231 : (eUnderline == UNDERLINE_DOUBLEWAVE) ||
4232 : (eUnderline == UNDERLINE_BOLDWAVE) )
4233 : {
4234 0 : ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
4235 0 : bUnderlineDone = sal_True;
4236 : }
4237 9 : if ( (eOverline == UNDERLINE_SMALLWAVE) ||
4238 : (eOverline == UNDERLINE_WAVE) ||
4239 : (eOverline == UNDERLINE_DOUBLEWAVE) ||
4240 : (eOverline == UNDERLINE_BOLDWAVE) )
4241 : {
4242 0 : ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
4243 0 : bOverlineDone = sal_True;
4244 : }
4245 :
4246 9 : if ( (eStrikeout == STRIKEOUT_SLASH) ||
4247 : (eStrikeout == STRIKEOUT_X) )
4248 : {
4249 0 : ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
4250 0 : bStrikeoutDone = sal_True;
4251 : }
4252 :
4253 9 : if ( !bUnderlineDone )
4254 9 : ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
4255 :
4256 9 : if ( !bOverlineDone )
4257 9 : ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
4258 :
4259 9 : if ( !bStrikeoutDone )
4260 9 : ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
4261 : }
4262 :
4263 : // -----------------------------------------------------------------------
4264 :
4265 9 : void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
4266 : FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, sal_Bool bWordLine, sal_Bool bUnderlineAbove )
4267 : {
4268 9 : if( bWordLine )
4269 : {
4270 : // draw everything relative to the layout base point
4271 0 : const Point aStartPt = rSalLayout.DrawBase();
4272 : // calculate distance of each word from the base point
4273 0 : Point aPos;
4274 0 : sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
4275 0 : for( int nStart = 0;;)
4276 : {
4277 : // iterate through the layouted glyphs
4278 : sal_GlyphId nGlyphIndex;
4279 0 : if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
4280 : break;
4281 :
4282 : // calculate the boundaries of each word
4283 0 : if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
4284 : {
4285 0 : if( !nWidth )
4286 : {
4287 : // get the distance to the base point (as projected to baseline)
4288 0 : nDist = aPos.X() - aStartPt.X();
4289 0 : if( mpFontEntry->mnOrientation )
4290 : {
4291 0 : const long nDY = aPos.Y() - aStartPt.Y();
4292 0 : const double fRad = mpFontEntry->mnOrientation * F_PI1800;
4293 0 : nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
4294 : }
4295 : }
4296 :
4297 : // update the length of the textline
4298 0 : nWidth += nAdvance;
4299 : }
4300 0 : else if( nWidth > 0 )
4301 : {
4302 : // draw the textline for each word
4303 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
4304 0 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4305 0 : nWidth = 0;
4306 : }
4307 : }
4308 :
4309 : // draw textline for the last word
4310 0 : if( nWidth > 0 )
4311 : {
4312 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
4313 0 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4314 : }
4315 : }
4316 : else
4317 : {
4318 9 : Point aStartPt = rSalLayout.GetDrawPosition();
4319 9 : int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
4320 18 : ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
4321 27 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4322 : }
4323 9 : }
4324 :
4325 : // -----------------------------------------------------------------------
4326 :
4327 0 : void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
4328 : {
4329 0 : long nBaseX = nX;
4330 0 : if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
4331 : {
4332 : // --- RTL ---
4333 : // add some strange offset
4334 0 : nX += 2;
4335 : // revert the hack that will be done later in ImplDrawTextLine
4336 0 : nX = nBaseX - nWidth - (nX - nBaseX - 1);
4337 : }
4338 :
4339 0 : ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False );
4340 0 : }
4341 :
4342 : // -----------------------------------------------------------------------
4343 :
4344 0 : void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, sal_Bool& rPolyLine,
4345 : Rectangle& rRect1, Rectangle& rRect2,
4346 : long& rYOff, long& rWidth,
4347 : FontEmphasisMark eEmphasis,
4348 : long nHeight, short /*nOrient*/ )
4349 : {
4350 : static const sal_uInt8 aAccentPolyFlags[24] =
4351 : {
4352 : 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
4353 : };
4354 :
4355 : static const long aAccentPos[48] =
4356 : {
4357 : 78, 0,
4358 : 348, 79,
4359 : 599, 235,
4360 : 843, 469,
4361 : 938, 574,
4362 : 990, 669,
4363 : 990, 773,
4364 : 990, 843,
4365 : 964, 895,
4366 : 921, 947,
4367 : 886, 982,
4368 : 860, 999,
4369 : 825, 999,
4370 : 764, 999,
4371 : 721, 964,
4372 : 686, 895,
4373 : 625, 791,
4374 : 556, 660,
4375 : 469, 504,
4376 : 400, 400,
4377 : 261, 252,
4378 : 61, 61,
4379 : 0, 27,
4380 : 9, 0
4381 : };
4382 :
4383 0 : rWidth = 0;
4384 0 : rYOff = 0;
4385 0 : rPolyLine = sal_False;
4386 :
4387 0 : if ( !nHeight )
4388 0 : return;
4389 :
4390 0 : FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
4391 0 : long nDotSize = 0;
4392 0 : switch ( nEmphasisStyle )
4393 : {
4394 : case EMPHASISMARK_DOT:
4395 : // Dot has 55% of the height
4396 0 : nDotSize = (nHeight*550)/1000;
4397 0 : if ( !nDotSize )
4398 0 : nDotSize = 1;
4399 0 : if ( nDotSize <= 2 )
4400 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4401 : else
4402 : {
4403 0 : long nRad = nDotSize/2;
4404 0 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4405 0 : rPolyPoly.Insert( aPoly );
4406 : }
4407 0 : rYOff = ((nHeight*250)/1000)/2; // Center to the anthoer EmphasisMarks
4408 0 : rWidth = nDotSize;
4409 0 : break;
4410 :
4411 : case EMPHASISMARK_CIRCLE:
4412 : // Dot has 80% of the height
4413 0 : nDotSize = (nHeight*800)/1000;
4414 0 : if ( !nDotSize )
4415 0 : nDotSize = 1;
4416 0 : if ( nDotSize <= 2 )
4417 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4418 : else
4419 : {
4420 0 : long nRad = nDotSize/2;
4421 0 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4422 0 : rPolyPoly.Insert( aPoly );
4423 : // BorderWidth is 15%
4424 0 : long nBorder = (nDotSize*150)/1000;
4425 0 : if ( nBorder <= 1 )
4426 0 : rPolyLine = sal_True;
4427 : else
4428 : {
4429 : Polygon aPoly2( Point( nRad, nRad ),
4430 0 : nRad-nBorder, nRad-nBorder );
4431 0 : rPolyPoly.Insert( aPoly2 );
4432 0 : }
4433 : }
4434 0 : rWidth = nDotSize;
4435 0 : break;
4436 :
4437 : case EMPHASISMARK_DISC:
4438 : // Dot has 80% of the height
4439 0 : nDotSize = (nHeight*800)/1000;
4440 0 : if ( !nDotSize )
4441 0 : nDotSize = 1;
4442 0 : if ( nDotSize <= 2 )
4443 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4444 : else
4445 : {
4446 0 : long nRad = nDotSize/2;
4447 0 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4448 0 : rPolyPoly.Insert( aPoly );
4449 : }
4450 0 : rWidth = nDotSize;
4451 0 : break;
4452 :
4453 : case EMPHASISMARK_ACCENT:
4454 : // Dot has 80% of the height
4455 0 : nDotSize = (nHeight*800)/1000;
4456 0 : if ( !nDotSize )
4457 0 : nDotSize = 1;
4458 0 : if ( nDotSize <= 2 )
4459 : {
4460 0 : if ( nDotSize == 1 )
4461 : {
4462 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4463 0 : rWidth = nDotSize;
4464 : }
4465 : else
4466 : {
4467 0 : rRect1 = Rectangle( Point(), Size( 1, 1 ) );
4468 0 : rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
4469 : }
4470 : }
4471 : else
4472 : {
4473 : Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
4474 : (const Point*)aAccentPos,
4475 0 : aAccentPolyFlags );
4476 0 : double dScale = ((double)nDotSize)/1000.0;
4477 0 : aPoly.Scale( dScale, dScale );
4478 0 : Polygon aTemp;
4479 0 : aPoly.AdaptiveSubdivide( aTemp );
4480 0 : Rectangle aBoundRect = aTemp.GetBoundRect();
4481 0 : rWidth = aBoundRect.GetWidth();
4482 0 : nDotSize = aBoundRect.GetHeight();
4483 0 : rPolyPoly.Insert( aTemp );
4484 : }
4485 0 : break;
4486 : }
4487 :
4488 : // calculate position
4489 0 : long nOffY = 1+(mnDPIY/300); // one visible pixel space
4490 0 : long nSpaceY = nHeight-nDotSize;
4491 0 : if ( nSpaceY >= nOffY*2 )
4492 0 : rYOff += nOffY;
4493 0 : if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
4494 0 : rYOff += nDotSize;
4495 : }
4496 :
4497 : // -----------------------------------------------------------------------
4498 :
4499 0 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
4500 : const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
4501 : const Rectangle& rRect1, const Rectangle& rRect2 )
4502 : {
4503 0 : if( IsRTLEnabled() )
4504 : // --- RTL --- mirror at basex
4505 0 : nX = nBaseX - (nX - nBaseX - 1);
4506 :
4507 0 : nX -= mnOutOffX;
4508 0 : nY -= mnOutOffY;
4509 :
4510 0 : if ( rPolyPoly.Count() )
4511 : {
4512 0 : if ( bPolyLine )
4513 : {
4514 0 : Polygon aPoly = rPolyPoly.GetObject( 0 );
4515 0 : aPoly.Move( nX, nY );
4516 0 : DrawPolyLine( aPoly );
4517 : }
4518 : else
4519 : {
4520 0 : PolyPolygon aPolyPoly = rPolyPoly;
4521 0 : aPolyPoly.Move( nX, nY );
4522 0 : DrawPolyPolygon( aPolyPoly );
4523 : }
4524 : }
4525 :
4526 0 : if ( !rRect1.IsEmpty() )
4527 : {
4528 0 : Rectangle aRect( Point( nX+rRect1.Left(),
4529 0 : nY+rRect1.Top() ), rRect1.GetSize() );
4530 0 : DrawRect( aRect );
4531 : }
4532 :
4533 0 : if ( !rRect2.IsEmpty() )
4534 : {
4535 0 : Rectangle aRect( Point( nX+rRect2.Left(),
4536 0 : nY+rRect2.Top() ), rRect2.GetSize() );
4537 :
4538 0 : DrawRect( aRect );
4539 : }
4540 0 : }
4541 :
4542 : // -----------------------------------------------------------------------
4543 :
4544 0 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
4545 : {
4546 0 : Color aOldLineColor = GetLineColor();
4547 0 : Color aOldFillColor = GetFillColor();
4548 0 : sal_Bool bOldMap = mbMap;
4549 0 : GDIMetaFile* pOldMetaFile = mpMetaFile;
4550 0 : mpMetaFile = NULL;
4551 0 : EnableMapMode( sal_False );
4552 :
4553 0 : FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
4554 0 : PolyPolygon aPolyPoly;
4555 0 : Rectangle aRect1;
4556 0 : Rectangle aRect2;
4557 : long nEmphasisYOff;
4558 : long nEmphasisWidth;
4559 : long nEmphasisHeight;
4560 : sal_Bool bPolyLine;
4561 :
4562 0 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
4563 0 : nEmphasisHeight = mnEmphasisDescent;
4564 : else
4565 0 : nEmphasisHeight = mnEmphasisAscent;
4566 :
4567 : ImplGetEmphasisMark( aPolyPoly, bPolyLine,
4568 : aRect1, aRect2,
4569 : nEmphasisYOff, nEmphasisWidth,
4570 : nEmphasisMark,
4571 0 : nEmphasisHeight, mpFontEntry->mnOrientation );
4572 :
4573 0 : if ( bPolyLine )
4574 : {
4575 0 : SetLineColor( GetTextColor() );
4576 0 : SetFillColor();
4577 : }
4578 : else
4579 : {
4580 0 : SetLineColor();
4581 0 : SetFillColor( GetTextColor() );
4582 : }
4583 :
4584 0 : Point aOffset = Point(0,0);
4585 :
4586 0 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
4587 0 : aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
4588 : else
4589 0 : aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
4590 :
4591 0 : long nEmphasisWidth2 = nEmphasisWidth / 2;
4592 0 : long nEmphasisHeight2 = nEmphasisHeight / 2;
4593 0 : aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
4594 :
4595 0 : Point aOutPoint;
4596 0 : Rectangle aRectangle;
4597 0 : for( int nStart = 0;;)
4598 : {
4599 : sal_GlyphId nGlyphIndex;
4600 0 : if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aOutPoint, nStart ) )
4601 : break;
4602 :
4603 0 : if( !mpGraphics->GetGlyphBoundRect( nGlyphIndex, aRectangle ) )
4604 0 : continue;
4605 :
4606 0 : if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
4607 : {
4608 0 : Point aAdjPoint = aOffset;
4609 0 : aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
4610 0 : if ( mpFontEntry->mnOrientation )
4611 0 : ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
4612 0 : aOutPoint += aAdjPoint;
4613 0 : aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
4614 0 : ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
4615 0 : aOutPoint.X(), aOutPoint.Y(),
4616 0 : aPolyPoly, bPolyLine, aRect1, aRect2 );
4617 : }
4618 : }
4619 :
4620 0 : SetLineColor( aOldLineColor );
4621 0 : SetFillColor( aOldFillColor );
4622 0 : EnableMapMode( bOldMap );
4623 0 : mpMetaFile = pOldMetaFile;
4624 0 : }
4625 :
4626 : // -----------------------------------------------------------------------
4627 :
4628 0 : bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
4629 : {
4630 0 : int nX = rSalLayout.DrawBase().X();
4631 0 : int nY = rSalLayout.DrawBase().Y();
4632 :
4633 0 : Rectangle aBoundRect;
4634 0 : rSalLayout.DrawBase() = Point( 0, 0 );
4635 0 : rSalLayout.DrawOffset() = Point( 0, 0 );
4636 0 : if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
4637 : {
4638 : // guess vertical text extents if GetBoundRect failed
4639 0 : int nRight = rSalLayout.GetTextWidth();
4640 0 : int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
4641 0 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
4642 0 : aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
4643 : }
4644 :
4645 : // cache virtual device for rotation
4646 0 : if ( !mpOutDevData )
4647 0 : ImplInitOutDevData();
4648 0 : if ( !mpOutDevData->mpRotateDev )
4649 0 : mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
4650 0 : VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
4651 :
4652 : // size it accordingly
4653 0 : if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
4654 0 : return false;
4655 :
4656 0 : Font aFont( GetFont() );
4657 0 : aFont.SetOrientation( 0 );
4658 0 : aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
4659 0 : pVDev->SetFont( aFont );
4660 0 : pVDev->SetTextColor( Color( COL_BLACK ) );
4661 0 : pVDev->SetTextFillColor();
4662 0 : pVDev->ImplNewFont();
4663 0 : pVDev->ImplInitFont();
4664 0 : pVDev->ImplInitTextColor();
4665 :
4666 : // draw text into upper left corner
4667 0 : rSalLayout.DrawBase() -= aBoundRect.TopLeft();
4668 0 : rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
4669 :
4670 0 : Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
4671 0 : if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
4672 0 : return false;
4673 :
4674 : // calculate rotation offset
4675 0 : Polygon aPoly( aBoundRect );
4676 0 : aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
4677 0 : Point aPoint = aPoly.GetBoundRect().TopLeft();
4678 0 : aPoint += Point( nX, nY );
4679 :
4680 : // mask output with text colored bitmap
4681 0 : GDIMetaFile* pOldMetaFile = mpMetaFile;
4682 0 : long nOldOffX = mnOutOffX;
4683 0 : long nOldOffY = mnOutOffY;
4684 0 : sal_Bool bOldMap = mbMap;
4685 :
4686 0 : mnOutOffX = 0L;
4687 0 : mnOutOffY = 0L;
4688 0 : mpMetaFile = NULL;
4689 0 : EnableMapMode( sal_False );
4690 :
4691 0 : DrawMask( aPoint, aBmp, GetTextColor() );
4692 :
4693 0 : EnableMapMode( bOldMap );
4694 0 : mnOutOffX = nOldOffX;
4695 0 : mnOutOffY = nOldOffY;
4696 0 : mpMetaFile = pOldMetaFile;
4697 :
4698 0 : return true;
4699 : }
4700 :
4701 : // -----------------------------------------------------------------------
4702 :
4703 7304 : void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, sal_Bool bTextLines )
4704 : {
4705 7304 : if( mpFontEntry->mnOwnOrientation )
4706 0 : if( ImplDrawRotateText( rSalLayout ) )
4707 7304 : return;
4708 :
4709 7304 : long nOldX = rSalLayout.DrawBase().X();
4710 7304 : if( ! (mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) )
4711 : {
4712 7304 : if( ImplHasMirroredGraphics() )
4713 : {
4714 0 : long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
4715 0 : long x = rSalLayout.DrawBase().X();
4716 0 : rSalLayout.DrawBase().X() = w - 1 - x;
4717 0 : if( !IsRTLEnabled() )
4718 : {
4719 0 : OutputDevice *pOutDevRef = (OutputDevice *)this;
4720 : // mirror this window back
4721 0 : long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
4722 0 : rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
4723 : }
4724 : }
4725 7304 : else if( IsRTLEnabled() )
4726 : {
4727 : //long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
4728 : //long x = rSalLayout.DrawBase().X();
4729 0 : OutputDevice *pOutDevRef = (OutputDevice *)this;
4730 : // mirror this window back
4731 0 : long devX = pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX
4732 0 : rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
4733 : }
4734 :
4735 7304 : rSalLayout.DrawText( *mpGraphics );
4736 : }
4737 :
4738 7304 : rSalLayout.DrawBase().X() = nOldX;
4739 :
4740 7304 : if( bTextLines )
4741 : ImplDrawTextLines( rSalLayout,
4742 : maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
4743 9 : maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
4744 :
4745 : // emphasis marks
4746 7304 : if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
4747 0 : ImplDrawEmphasisMarks( rSalLayout );
4748 : }
4749 :
4750 : // -----------------------------------------------------------------------
4751 :
4752 0 : void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
4753 : {
4754 0 : Color aOldColor = GetTextColor();
4755 0 : Color aOldTextLineColor = GetTextLineColor();
4756 0 : Color aOldOverlineColor = GetOverlineColor();
4757 0 : FontRelief eRelief = maFont.GetRelief();
4758 :
4759 0 : Point aOrigPos = rSalLayout.DrawBase();
4760 0 : if ( eRelief != RELIEF_NONE )
4761 : {
4762 0 : Color aReliefColor( COL_LIGHTGRAY );
4763 0 : Color aTextColor( aOldColor );
4764 :
4765 0 : Color aTextLineColor( aOldTextLineColor );
4766 0 : Color aOverlineColor( aOldOverlineColor );
4767 :
4768 : // we don't have a automatic color, so black is always drawn on white
4769 0 : if ( aTextColor.GetColor() == COL_BLACK )
4770 0 : aTextColor = Color( COL_WHITE );
4771 0 : if ( aTextLineColor.GetColor() == COL_BLACK )
4772 0 : aTextLineColor = Color( COL_WHITE );
4773 0 : if ( aOverlineColor.GetColor() == COL_BLACK )
4774 0 : aOverlineColor = Color( COL_WHITE );
4775 :
4776 : // relief-color is black for white text, in all other cases
4777 : // we set this to LightGray
4778 0 : if ( aTextColor.GetColor() == COL_WHITE )
4779 0 : aReliefColor = Color( COL_BLACK );
4780 0 : SetTextLineColor( aReliefColor );
4781 0 : SetOverlineColor( aReliefColor );
4782 0 : SetTextColor( aReliefColor );
4783 0 : ImplInitTextColor();
4784 :
4785 : // calculate offset - for high resolution printers the offset
4786 : // should be greater so that the effect is visible
4787 0 : long nOff = 1;
4788 0 : nOff += mnDPIX/300;
4789 :
4790 0 : if ( eRelief == RELIEF_ENGRAVED )
4791 0 : nOff = -nOff;
4792 0 : rSalLayout.DrawOffset() += Point( nOff, nOff);
4793 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4794 0 : rSalLayout.DrawOffset() -= Point( nOff, nOff);
4795 :
4796 0 : SetTextLineColor( aTextLineColor );
4797 0 : SetOverlineColor( aOverlineColor );
4798 0 : SetTextColor( aTextColor );
4799 0 : ImplInitTextColor();
4800 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4801 :
4802 0 : SetTextLineColor( aOldTextLineColor );
4803 0 : SetOverlineColor( aOldOverlineColor );
4804 :
4805 0 : if ( aTextColor != aOldColor )
4806 : {
4807 0 : SetTextColor( aOldColor );
4808 0 : ImplInitTextColor();
4809 : }
4810 : }
4811 : else
4812 : {
4813 0 : if ( maFont.IsShadow() )
4814 : {
4815 0 : long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
4816 0 : if ( maFont.IsOutline() )
4817 0 : nOff++;
4818 0 : SetTextLineColor();
4819 0 : SetOverlineColor();
4820 0 : if ( (GetTextColor().GetColor() == COL_BLACK)
4821 0 : || (GetTextColor().GetLuminance() < 8) )
4822 0 : SetTextColor( Color( COL_LIGHTGRAY ) );
4823 : else
4824 0 : SetTextColor( Color( COL_BLACK ) );
4825 0 : ImplInitTextColor();
4826 0 : rSalLayout.DrawBase() += Point( nOff, nOff );
4827 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4828 0 : rSalLayout.DrawBase() -= Point( nOff, nOff );
4829 0 : SetTextColor( aOldColor );
4830 0 : SetTextLineColor( aOldTextLineColor );
4831 0 : SetOverlineColor( aOldOverlineColor );
4832 0 : ImplInitTextColor();
4833 :
4834 0 : if ( !maFont.IsOutline() )
4835 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4836 : }
4837 :
4838 0 : if ( maFont.IsOutline() )
4839 : {
4840 0 : rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
4841 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4842 0 : rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
4843 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4844 0 : rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
4845 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4846 0 : rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
4847 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4848 0 : rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
4849 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4850 0 : rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
4851 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4852 0 : rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
4853 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4854 0 : rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
4855 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4856 0 : rSalLayout.DrawBase() = aOrigPos;
4857 :
4858 0 : SetTextColor( Color( COL_WHITE ) );
4859 0 : SetTextLineColor( Color( COL_WHITE ) );
4860 0 : SetOverlineColor( Color( COL_WHITE ) );
4861 0 : ImplInitTextColor();
4862 0 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4863 0 : SetTextColor( aOldColor );
4864 0 : SetTextLineColor( aOldTextLineColor );
4865 0 : SetOverlineColor( aOldOverlineColor );
4866 0 : ImplInitTextColor();
4867 : }
4868 : }
4869 0 : }
4870 :
4871 : // -----------------------------------------------------------------------
4872 :
4873 7322 : void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
4874 : {
4875 7322 : if( mbInitClipRegion )
4876 162 : ImplInitClipRegion();
4877 7322 : if( mbOutputClipped )
4878 7340 : return;
4879 7304 : if( mbInitTextColor )
4880 1330 : ImplInitTextColor();
4881 :
4882 7304 : rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
4883 :
4884 7304 : if( IsTextFillColor() )
4885 0 : ImplDrawTextBackground( rSalLayout );
4886 :
4887 7304 : if( mbTextSpecial )
4888 0 : ImplDrawSpecialText( rSalLayout );
4889 : else
4890 7304 : ImplDrawTextDirect( rSalLayout, mbTextLines );
4891 : }
4892 :
4893 : // -----------------------------------------------------------------------
4894 :
4895 0 : long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
4896 : long nWidth, const XubString& rStr,
4897 : sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
4898 : {
4899 : DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
4900 :
4901 0 : if ( nWidth <= 0 )
4902 0 : nWidth = 1;
4903 :
4904 0 : long nMaxLineWidth = 0;
4905 0 : rLineInfo.Clear();
4906 0 : if ( rStr.Len() && (nWidth > 0) )
4907 : {
4908 0 : ::rtl::OUString aText( rStr );
4909 0 : uno::Reference < i18n::XBreakIterator > xBI;
4910 : // get service provider
4911 0 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
4912 :
4913 0 : uno::Reference< linguistic2::XLinguServiceManager2> xLinguMgr = linguistic2::LinguServiceManager::create(xContext);
4914 0 : uno::Reference< linguistic2::XHyphenator > xHyph = xLinguMgr->getHyphenator();
4915 :
4916 0 : i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
4917 0 : i18n::LineBreakUserOptions aUserOptions;
4918 :
4919 0 : xub_StrLen nPos = 0;
4920 0 : xub_StrLen nLen = rStr.Len();
4921 0 : while ( nPos < nLen )
4922 : {
4923 0 : xub_StrLen nBreakPos = nPos;
4924 :
4925 0 : while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
4926 0 : nBreakPos++;
4927 :
4928 0 : long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
4929 0 : if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
4930 : {
4931 0 : if ( !xBI.is() )
4932 0 : xBI = vcl::unohelper::CreateBreakIterator();
4933 :
4934 0 : if ( xBI.is() )
4935 : {
4936 0 : const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
4937 0 : xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
4938 : DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
4939 : //aHyphOptions.hyphenIndex = nSoftBreak;
4940 0 : i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
4941 0 : nBreakPos = (xub_StrLen)aLBR.breakIndex;
4942 0 : if ( nBreakPos <= nPos )
4943 0 : nBreakPos = nSoftBreak;
4944 0 : if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
4945 : {
4946 : // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
4947 : // die Silbentrennung jagen...
4948 : // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
4949 : // nBreakPos ist der Wort-Anfang
4950 : // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
4951 : // auf mehr als Zwei Zeilen gebrochen wird...
4952 0 : if ( xHyph.is() )
4953 : {
4954 0 : sal_Unicode cAlternateReplChar = 0;
4955 0 : i18n::Boundary aBoundary = xBI->getWordBoundary( aText, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
4956 : // sal_uInt16 nWordStart = nBreakPos;
4957 : // sal_uInt16 nBreakPos_OLD = nBreakPos;
4958 0 : sal_uInt16 nWordStart = nPos;
4959 0 : sal_uInt16 nWordEnd = (sal_uInt16) aBoundary.endPos;
4960 : DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
4961 :
4962 0 : sal_uInt16 nWordLen = nWordEnd - nWordStart;
4963 0 : if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
4964 : {
4965 : // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
4966 : // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
4967 0 : String aWord( aText, nWordStart, nWordLen );
4968 0 : sal_uInt16 nMinTrail = static_cast<sal_uInt16>(nWordEnd-nSoftBreak+1); //+1: Vor dem angeknacksten Buchstaben
4969 0 : uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
4970 0 : if (xHyph.is())
4971 0 : xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.Len() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
4972 0 : if (xHyphWord.is())
4973 : {
4974 0 : sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
4975 0 : sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
4976 :
4977 0 : if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
4978 : {
4979 0 : if ( !bAlternate )
4980 : {
4981 0 : nBreakPos = nWordStart + _nWordLen;
4982 : }
4983 : else
4984 : {
4985 0 : String aAlt( xHyphWord->getHyphenatedWord() );
4986 :
4987 : // Wir gehen von zwei Faellen aus, die nun
4988 : // vorliegen koennen:
4989 : // 1) packen wird zu pak-ken
4990 : // 2) Schiffahrt wird zu Schiff-fahrt
4991 : // In Fall 1 muss ein Zeichen ersetzt werden,
4992 : // in Fall 2 wird ein Zeichen hinzugefuegt.
4993 : // Die Identifikation wird erschwert durch Worte wie
4994 : // "Schiffahrtsbrennesseln", da der Hyphenator alle
4995 : // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
4996 : // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
4997 : // Index des AlternativWord auf aWord schliessen.
4998 :
4999 : // Das ganze geraffel wird durch eine Funktion am
5000 : // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
5001 0 : sal_uInt16 nAltStart = _nWordLen - 1;
5002 0 : sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
5003 0 : sal_uInt16 nTxtEnd = nTxtStart;
5004 0 : sal_uInt16 nAltEnd = nAltStart;
5005 :
5006 : // Die Bereiche zwischen den nStart und nEnd ist
5007 : // die Differenz zwischen Alternativ- und OriginalString.
5008 0 : while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
5009 0 : aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
5010 : {
5011 0 : ++nTxtEnd;
5012 0 : ++nAltEnd;
5013 : }
5014 :
5015 : // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
5016 0 : if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
5017 0 : aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
5018 : {
5019 0 : ++nAltEnd;
5020 0 : ++nTxtStart;
5021 0 : ++nTxtEnd;
5022 : }
5023 :
5024 : DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" );
5025 :
5026 0 : if ( nTxtEnd > nTxtStart )
5027 0 : cAlternateReplChar = aAlt.GetChar( nAltStart );
5028 :
5029 0 : nBreakPos = nWordStart + nTxtStart;
5030 0 : if ( cAlternateReplChar )
5031 0 : nBreakPos++;
5032 : }
5033 : } // if (xHyphWord.is())
5034 0 : } // if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
5035 : } // if ( xHyph.is() )
5036 : } // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
5037 : }
5038 0 : nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
5039 : }
5040 : else
5041 : {
5042 : // fallback to something really simple
5043 0 : sal_uInt16 nSpacePos = STRING_LEN;
5044 0 : long nW = 0;
5045 0 : do
5046 : {
5047 0 : nSpacePos = rStr.SearchBackward( sal_Unicode(' '), nSpacePos );
5048 0 : if( nSpacePos != STRING_NOTFOUND )
5049 : {
5050 0 : if( nSpacePos > nPos )
5051 0 : nSpacePos--;
5052 0 : nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
5053 : }
5054 : } while( nW > nWidth );
5055 :
5056 0 : if( nSpacePos != STRING_NOTFOUND )
5057 : {
5058 0 : nBreakPos = nSpacePos;
5059 0 : nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
5060 0 : if( nBreakPos < rStr.Len()-1 )
5061 0 : nBreakPos++;
5062 : }
5063 : }
5064 : }
5065 :
5066 0 : if ( nLineWidth > nMaxLineWidth )
5067 0 : nMaxLineWidth = nLineWidth;
5068 :
5069 0 : rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
5070 :
5071 0 : if ( nBreakPos == nPos )
5072 0 : nBreakPos++;
5073 0 : nPos = nBreakPos;
5074 :
5075 0 : if ( ( rStr.GetChar( nPos ) == _CR ) || ( rStr.GetChar( nPos ) == _LF ) )
5076 : {
5077 0 : nPos++;
5078 : // CR/LF?
5079 0 : if ( ( nPos < nLen ) && ( rStr.GetChar( nPos ) == _LF ) && ( rStr.GetChar( nPos-1 ) == _CR ) )
5080 0 : nPos++;
5081 : }
5082 0 : }
5083 : }
5084 : #ifdef DBG_UTIL
5085 : for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
5086 : {
5087 : ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
5088 : String aLine( rStr, pLine->GetIndex(), pLine->GetLen() );
5089 : DBG_ASSERT( aLine.Search( _CR ) == STRING_NOTFOUND, "ImplGetTextLines - Found CR!" );
5090 : DBG_ASSERT( aLine.Search( _LF ) == STRING_NOTFOUND, "ImplGetTextLines - Found LF!" );
5091 : }
5092 : #endif
5093 :
5094 0 : return nMaxLineWidth;
5095 : }
5096 :
5097 : // =======================================================================
5098 :
5099 3420 : void OutputDevice::SetAntialiasing( sal_uInt16 nMode )
5100 : {
5101 3420 : if ( mnAntialiasing != nMode )
5102 : {
5103 395 : mnAntialiasing = nMode;
5104 395 : mbInitFont = sal_True;
5105 :
5106 395 : if(mpGraphics)
5107 : {
5108 0 : mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
5109 : }
5110 : }
5111 :
5112 3420 : if( mpAlphaVDev )
5113 0 : mpAlphaVDev->SetAntialiasing( nMode );
5114 3420 : }
5115 :
5116 : // -----------------------------------------------------------------------
5117 :
5118 122104 : void OutputDevice::SetFont( const Font& rNewFont )
5119 : {
5120 : OSL_TRACE( "OutputDevice::SetFont()" );
5121 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5122 : DBG_CHKOBJ( &rNewFont, Font, NULL );
5123 :
5124 122104 : Font aFont( rNewFont );
5125 122104 : aFont.SetLanguage(rNewFont.GetLanguage());
5126 122104 : if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
5127 : DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
5128 : DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
5129 : {
5130 0 : Color aTextColor( aFont.GetColor() );
5131 :
5132 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5133 0 : aTextColor = Color( COL_BLACK );
5134 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5135 0 : aTextColor = Color( COL_WHITE );
5136 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5137 : {
5138 0 : const sal_uInt8 cLum = aTextColor.GetLuminance();
5139 0 : aTextColor = Color( cLum, cLum, cLum );
5140 : }
5141 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5142 0 : aTextColor = GetSettings().GetStyleSettings().GetFontColor();
5143 :
5144 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
5145 : {
5146 0 : aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
5147 0 : (aTextColor.GetGreen() >> 1 ) | 0x80,
5148 0 : (aTextColor.GetBlue() >> 1 ) | 0x80 );
5149 : }
5150 :
5151 0 : aFont.SetColor( aTextColor );
5152 :
5153 0 : sal_Bool bTransFill = aFont.IsTransparent();
5154 0 : if ( !bTransFill )
5155 : {
5156 0 : Color aTextFillColor( aFont.GetFillColor() );
5157 :
5158 0 : if ( mnDrawMode & DRAWMODE_BLACKFILL )
5159 0 : aTextFillColor = Color( COL_BLACK );
5160 0 : else if ( mnDrawMode & DRAWMODE_WHITEFILL )
5161 0 : aTextFillColor = Color( COL_WHITE );
5162 0 : else if ( mnDrawMode & DRAWMODE_GRAYFILL )
5163 : {
5164 0 : const sal_uInt8 cLum = aTextFillColor.GetLuminance();
5165 0 : aTextFillColor = Color( cLum, cLum, cLum );
5166 : }
5167 0 : else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
5168 0 : aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
5169 0 : else if ( mnDrawMode & DRAWMODE_NOFILL )
5170 : {
5171 0 : aTextFillColor = Color( COL_TRANSPARENT );
5172 0 : bTransFill = sal_True;
5173 : }
5174 :
5175 0 : if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
5176 : {
5177 0 : aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
5178 0 : (aTextFillColor.GetGreen() >> 1) | 0x80,
5179 0 : (aTextFillColor.GetBlue() >> 1) | 0x80 );
5180 : }
5181 :
5182 0 : aFont.SetFillColor( aTextFillColor );
5183 : }
5184 : }
5185 :
5186 122104 : if ( mpMetaFile )
5187 : {
5188 22006 : mpMetaFile->AddAction( new MetaFontAction( aFont ) );
5189 : // the color and alignment actions don't belong here
5190 : // TODO: get rid of them without breaking anything...
5191 22006 : mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
5192 22006 : mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
5193 : }
5194 :
5195 122104 : if ( !maFont.IsSameInstance( aFont ) )
5196 : {
5197 : // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
5198 : // because SetTextColor() is used for this.
5199 : // #i28759# maTextColor might have been changed behind our back, commit then, too.
5200 135339 : if( aFont.GetColor() != COL_TRANSPARENT
5201 18834 : && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
5202 : {
5203 4944 : maTextColor = aFont.GetColor();
5204 4944 : mbInitTextColor = sal_True;
5205 4944 : if( mpMetaFile )
5206 199 : mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
5207 : }
5208 116505 : maFont = aFont;
5209 116505 : mbNewFont = sal_True;
5210 :
5211 116505 : if( mpAlphaVDev )
5212 : {
5213 : // #i30463#
5214 : // Since SetFont might change the text color, apply that only
5215 : // selectively to alpha vdev (which normally paints opaque text
5216 : // with COL_BLACK)
5217 0 : if( aFont.GetColor() != COL_TRANSPARENT )
5218 : {
5219 0 : mpAlphaVDev->SetTextColor( COL_BLACK );
5220 0 : aFont.SetColor( COL_TRANSPARENT );
5221 : }
5222 :
5223 0 : mpAlphaVDev->SetFont( aFont );
5224 : }
5225 122104 : }
5226 122104 : }
5227 :
5228 : // -----------------------------------------------------------------------
5229 :
5230 39772 : void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode )
5231 : {
5232 : OSL_TRACE( "OutputDevice::SetTextLayoutMode()" );
5233 :
5234 39772 : if( mpMetaFile )
5235 4581 : mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
5236 :
5237 39772 : mnTextLayoutMode = nTextLayoutMode;
5238 :
5239 39772 : if( mpAlphaVDev )
5240 0 : mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
5241 39772 : }
5242 :
5243 : // -----------------------------------------------------------------------
5244 :
5245 59419 : void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
5246 : {
5247 : OSL_TRACE( "OutputDevice::SetTextLanguage()" );
5248 :
5249 59419 : if( mpMetaFile )
5250 6892 : mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
5251 :
5252 59419 : meTextLanguage = eTextLanguage;
5253 :
5254 59419 : if( mpAlphaVDev )
5255 0 : mpAlphaVDev->SetDigitLanguage( eTextLanguage );
5256 59419 : }
5257 :
5258 : // -----------------------------------------------------------------------
5259 :
5260 82780 : void OutputDevice::SetTextColor( const Color& rColor )
5261 : {
5262 : OSL_TRACE( "OutputDevice::SetTextColor()" );
5263 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5264 :
5265 82780 : Color aColor( rColor );
5266 :
5267 82780 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5268 : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5269 : DRAWMODE_SETTINGSTEXT ) )
5270 : {
5271 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5272 0 : aColor = Color( COL_BLACK );
5273 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5274 0 : aColor = Color( COL_WHITE );
5275 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5276 : {
5277 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5278 0 : aColor = Color( cLum, cLum, cLum );
5279 : }
5280 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5281 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
5282 :
5283 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
5284 : {
5285 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5286 0 : (aColor.GetGreen() >> 1) | 0x80,
5287 0 : (aColor.GetBlue() >> 1) | 0x80 );
5288 : }
5289 : }
5290 :
5291 82780 : if ( mpMetaFile )
5292 21989 : mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
5293 :
5294 82780 : if ( maTextColor != aColor )
5295 : {
5296 759 : maTextColor = aColor;
5297 759 : mbInitTextColor = sal_True;
5298 : }
5299 :
5300 82780 : if( mpAlphaVDev )
5301 0 : mpAlphaVDev->SetTextColor( COL_BLACK );
5302 82780 : }
5303 :
5304 : // -----------------------------------------------------------------------
5305 :
5306 9622 : void OutputDevice::SetTextFillColor()
5307 : {
5308 : OSL_TRACE( "OutputDevice::SetTextFillColor()" );
5309 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5310 :
5311 9622 : if ( mpMetaFile )
5312 0 : mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), sal_False ) );
5313 :
5314 9622 : if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
5315 251 : maFont.SetFillColor( Color( COL_TRANSPARENT ) );
5316 9622 : if ( !maFont.IsTransparent() )
5317 0 : maFont.SetTransparent( sal_True );
5318 :
5319 9622 : if( mpAlphaVDev )
5320 0 : mpAlphaVDev->SetTextFillColor();
5321 9622 : }
5322 :
5323 : // -----------------------------------------------------------------------
5324 :
5325 490 : void OutputDevice::SetTextFillColor( const Color& rColor )
5326 : {
5327 : OSL_TRACE( "OutputDevice::SetTextFillColor()" );
5328 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5329 :
5330 490 : Color aColor( rColor );
5331 490 : sal_Bool bTransFill = ImplIsColorTransparent( aColor ) ? sal_True : sal_False;
5332 :
5333 490 : if ( !bTransFill )
5334 : {
5335 18 : if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
5336 : DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
5337 : DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
5338 : {
5339 0 : if ( mnDrawMode & DRAWMODE_BLACKFILL )
5340 0 : aColor = Color( COL_BLACK );
5341 0 : else if ( mnDrawMode & DRAWMODE_WHITEFILL )
5342 0 : aColor = Color( COL_WHITE );
5343 0 : else if ( mnDrawMode & DRAWMODE_GRAYFILL )
5344 : {
5345 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5346 0 : aColor = Color( cLum, cLum, cLum );
5347 : }
5348 0 : else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
5349 0 : aColor = GetSettings().GetStyleSettings().GetWindowColor();
5350 0 : else if ( mnDrawMode & DRAWMODE_NOFILL )
5351 : {
5352 0 : aColor = Color( COL_TRANSPARENT );
5353 0 : bTransFill = sal_True;
5354 : }
5355 :
5356 0 : if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
5357 : {
5358 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5359 0 : (aColor.GetGreen() >> 1) | 0x80,
5360 0 : (aColor.GetBlue() >> 1) | 0x80 );
5361 : }
5362 : }
5363 : }
5364 :
5365 490 : if ( mpMetaFile )
5366 0 : mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, sal_True ) );
5367 :
5368 490 : if ( maFont.GetFillColor() != aColor )
5369 6 : maFont.SetFillColor( aColor );
5370 490 : if ( maFont.IsTransparent() != bTransFill )
5371 6 : maFont.SetTransparent( bTransFill );
5372 :
5373 490 : if( mpAlphaVDev )
5374 0 : mpAlphaVDev->SetTextFillColor( COL_BLACK );
5375 490 : }
5376 :
5377 : // -----------------------------------------------------------------------
5378 :
5379 472 : Color OutputDevice::GetTextFillColor() const
5380 : {
5381 472 : if ( maFont.IsTransparent() )
5382 472 : return Color( COL_TRANSPARENT );
5383 : else
5384 0 : return maFont.GetFillColor();
5385 : }
5386 :
5387 : // -----------------------------------------------------------------------
5388 :
5389 3067 : void OutputDevice::SetTextLineColor()
5390 : {
5391 : OSL_TRACE( "OutputDevice::SetTextLineColor()" );
5392 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5393 :
5394 3067 : if ( mpMetaFile )
5395 0 : mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), sal_False ) );
5396 :
5397 3067 : maTextLineColor = Color( COL_TRANSPARENT );
5398 :
5399 3067 : if( mpAlphaVDev )
5400 0 : mpAlphaVDev->SetTextLineColor();
5401 3067 : }
5402 :
5403 : // -----------------------------------------------------------------------
5404 :
5405 23 : void OutputDevice::SetTextLineColor( const Color& rColor )
5406 : {
5407 : OSL_TRACE( "OutputDevice::SetTextLineColor()" );
5408 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5409 :
5410 23 : Color aColor( rColor );
5411 :
5412 23 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5413 : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5414 : DRAWMODE_SETTINGSTEXT ) )
5415 : {
5416 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5417 0 : aColor = Color( COL_BLACK );
5418 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5419 0 : aColor = Color( COL_WHITE );
5420 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5421 : {
5422 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5423 0 : aColor = Color( cLum, cLum, cLum );
5424 : }
5425 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5426 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
5427 :
5428 0 : if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
5429 0 : && (aColor.GetColor() != COL_TRANSPARENT) )
5430 : {
5431 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5432 0 : (aColor.GetGreen() >> 1) | 0x80,
5433 0 : (aColor.GetBlue() >> 1) | 0x80 );
5434 : }
5435 : }
5436 :
5437 23 : if ( mpMetaFile )
5438 1 : mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, sal_True ) );
5439 :
5440 23 : maTextLineColor = aColor;
5441 :
5442 23 : if( mpAlphaVDev )
5443 0 : mpAlphaVDev->SetTextLineColor( COL_BLACK );
5444 23 : }
5445 :
5446 : // -----------------------------------------------------------------------
5447 :
5448 3067 : void OutputDevice::SetOverlineColor()
5449 : {
5450 : OSL_TRACE( "OutputDevice::SetOverlineColor()" );
5451 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5452 :
5453 3067 : if ( mpMetaFile )
5454 0 : mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), sal_False ) );
5455 :
5456 3067 : maOverlineColor = Color( COL_TRANSPARENT );
5457 :
5458 3067 : if( mpAlphaVDev )
5459 0 : mpAlphaVDev->SetOverlineColor();
5460 3067 : }
5461 :
5462 : // -----------------------------------------------------------------------
5463 :
5464 14 : void OutputDevice::SetOverlineColor( const Color& rColor )
5465 : {
5466 : OSL_TRACE( "OutputDevice::SetOverlineColor()" );
5467 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5468 :
5469 14 : Color aColor( rColor );
5470 :
5471 14 : if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5472 : DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5473 : DRAWMODE_SETTINGSTEXT ) )
5474 : {
5475 0 : if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5476 0 : aColor = Color( COL_BLACK );
5477 0 : else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5478 0 : aColor = Color( COL_WHITE );
5479 0 : else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5480 : {
5481 0 : const sal_uInt8 cLum = aColor.GetLuminance();
5482 0 : aColor = Color( cLum, cLum, cLum );
5483 : }
5484 0 : else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5485 0 : aColor = GetSettings().GetStyleSettings().GetFontColor();
5486 :
5487 0 : if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
5488 0 : && (aColor.GetColor() != COL_TRANSPARENT) )
5489 : {
5490 0 : aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5491 0 : (aColor.GetGreen() >> 1) | 0x80,
5492 0 : (aColor.GetBlue() >> 1) | 0x80 );
5493 : }
5494 : }
5495 :
5496 14 : if ( mpMetaFile )
5497 1 : mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, sal_True ) );
5498 :
5499 14 : maOverlineColor = aColor;
5500 :
5501 14 : if( mpAlphaVDev )
5502 0 : mpAlphaVDev->SetOverlineColor( COL_BLACK );
5503 14 : }
5504 :
5505 : // -----------------------------------------------------------------------
5506 :
5507 :
5508 5282 : void OutputDevice::SetTextAlign( TextAlign eAlign )
5509 : {
5510 : OSL_TRACE( "OutputDevice::SetTextAlign()" );
5511 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5512 :
5513 5282 : if ( mpMetaFile )
5514 0 : mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
5515 :
5516 5282 : if ( maFont.GetAlign() != eAlign )
5517 : {
5518 1965 : maFont.SetAlign( eAlign );
5519 1965 : mbNewFont = sal_True;
5520 : }
5521 :
5522 5282 : if( mpAlphaVDev )
5523 0 : mpAlphaVDev->SetTextAlign( eAlign );
5524 5282 : }
5525 :
5526 : // -----------------------------------------------------------------------
5527 :
5528 0 : void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
5529 : FontStrikeout eStrikeout,
5530 : FontUnderline eUnderline,
5531 : FontUnderline eOverline,
5532 : sal_Bool bUnderlineAbove )
5533 : {
5534 : OSL_TRACE( "OutputDevice::DrawTextLine()" );
5535 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5536 :
5537 0 : if ( mpMetaFile )
5538 0 : mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
5539 :
5540 0 : if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
5541 : ((eOverline == UNDERLINE_NONE) || (eOverline == UNDERLINE_DONTKNOW)) &&
5542 : ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
5543 : return;
5544 :
5545 0 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
5546 : return;
5547 :
5548 : // we need a graphics
5549 0 : if( !mpGraphics && !ImplGetGraphics() )
5550 : return;
5551 0 : if( mbInitClipRegion )
5552 0 : ImplInitClipRegion();
5553 0 : if( mbOutputClipped )
5554 : return;
5555 :
5556 : // initialize font if needed to get text offsets
5557 : // TODO: only needed for mnTextOff!=(0,0)
5558 0 : if( mbNewFont )
5559 0 : if( !ImplNewFont() )
5560 : return;
5561 0 : if( mbInitFont )
5562 0 : ImplInitFont();
5563 :
5564 0 : Point aPos = ImplLogicToDevicePixel( rPos );
5565 0 : nWidth = ImplLogicWidthToDevicePixel( nWidth );
5566 0 : aPos += Point( mnTextOffX, mnTextOffY );
5567 0 : ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
5568 :
5569 0 : if( mpAlphaVDev )
5570 0 : mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
5571 : }
5572 :
5573 : // ------------------------------------------------------------------------
5574 :
5575 0 : void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
5576 : sal_uInt16 nStyle )
5577 : {
5578 : OSL_TRACE( "OutputDevice::DrawWaveLine()" );
5579 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5580 :
5581 0 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
5582 : return;
5583 :
5584 : // we need a graphics
5585 0 : if( !mpGraphics )
5586 0 : if( !ImplGetGraphics() )
5587 : return;
5588 :
5589 0 : if ( mbInitClipRegion )
5590 0 : ImplInitClipRegion();
5591 0 : if ( mbOutputClipped )
5592 : return;
5593 :
5594 0 : if( mbNewFont )
5595 0 : if( !ImplNewFont() )
5596 : return;
5597 :
5598 0 : Point aStartPt = ImplLogicToDevicePixel( rStartPos );
5599 0 : Point aEndPt = ImplLogicToDevicePixel( rEndPos );
5600 0 : long nStartX = aStartPt.X();
5601 0 : long nStartY = aStartPt.Y();
5602 0 : long nEndX = aEndPt.X();
5603 0 : long nEndY = aEndPt.Y();
5604 0 : short nOrientation = 0;
5605 :
5606 : // when rotated
5607 0 : if ( (nStartY != nEndY) || (nStartX > nEndX) )
5608 : {
5609 0 : long nDX = nEndX - nStartX;
5610 0 : double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
5611 0 : nO /= F_PI1800;
5612 0 : nOrientation = (short)nO;
5613 0 : ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
5614 : }
5615 :
5616 : long nWaveHeight;
5617 0 : if ( nStyle == WAVE_NORMAL )
5618 : {
5619 0 : nWaveHeight = 3;
5620 0 : nStartY++;
5621 0 : nEndY++;
5622 : }
5623 0 : else if( nStyle == WAVE_SMALL )
5624 : {
5625 0 : nWaveHeight = 2;
5626 0 : nStartY++;
5627 0 : nEndY++;
5628 : }
5629 : else // WAVE_FLAT
5630 0 : nWaveHeight = 1;
5631 :
5632 : // #109280# make sure the waveline does not exceed the descent to avoid paint problems
5633 0 : ImplFontEntry* pFontEntry = mpFontEntry;
5634 0 : if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
5635 0 : nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
5636 :
5637 : ImplDrawWaveLine( nStartX, nStartY, 0, 0,
5638 : nEndX-nStartX, nWaveHeight, 1,
5639 0 : nOrientation, GetLineColor() );
5640 0 : if( mpAlphaVDev )
5641 0 : mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nStyle );
5642 : }
5643 :
5644 : // -----------------------------------------------------------------------
5645 :
5646 5400 : void OutputDevice::DrawText( const Point& rStartPt, const String& rStr,
5647 : xub_StrLen nIndex, xub_StrLen nLen,
5648 : MetricVector* pVector, String* pDisplayText
5649 : )
5650 : {
5651 5400 : if( mpOutDevData && mpOutDevData->mpRecordLayout )
5652 : {
5653 0 : pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
5654 0 : pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
5655 : }
5656 :
5657 : OSL_TRACE( "OutputDevice::DrawText()" );
5658 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5659 :
5660 : #if OSL_DEBUG_LEVEL > 2
5661 : fprintf( stderr, " OutputDevice::DrawText(\"%s\")\n",
5662 : OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
5663 : #endif
5664 :
5665 5400 : if ( mpMetaFile )
5666 0 : mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
5667 5400 : if( pVector )
5668 : {
5669 0 : Region aClip( GetClipRegion() );
5670 0 : if( meOutDevType == OUTDEV_WINDOW )
5671 0 : aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
5672 0 : if( mpOutDevData && mpOutDevData->mpRecordLayout )
5673 : {
5674 0 : mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.Len() );
5675 0 : aClip.Intersect( mpOutDevData->maRecordRect );
5676 : }
5677 0 : if( ! aClip.IsNull() )
5678 : {
5679 0 : MetricVector aTmp;
5680 0 : GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
5681 :
5682 0 : bool bInserted = false;
5683 0 : for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
5684 : {
5685 0 : bool bAppend = false;
5686 :
5687 0 : if( aClip.IsOver( *it ) )
5688 0 : bAppend = true;
5689 0 : else if( rStr.GetChar( nIndex ) == ' ' && bInserted )
5690 : {
5691 0 : MetricVector::const_iterator next = it;
5692 0 : ++next;
5693 0 : if( next != aTmp.end() && aClip.IsOver( *next ) )
5694 0 : bAppend = true;
5695 : }
5696 :
5697 0 : if( bAppend )
5698 : {
5699 0 : pVector->push_back( *it );
5700 0 : if( pDisplayText )
5701 0 : pDisplayText->Append( rStr.GetChar( nIndex ) );
5702 0 : bInserted = true;
5703 : }
5704 0 : }
5705 : }
5706 : else
5707 : {
5708 0 : GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
5709 0 : if( pDisplayText )
5710 0 : pDisplayText->Append( rStr.Copy( nIndex, nLen ) );
5711 0 : }
5712 : }
5713 :
5714 5400 : if ( !IsDeviceOutputNecessary() || pVector )
5715 5400 : return;
5716 :
5717 5400 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, NULL, true );
5718 5400 : if( pSalLayout )
5719 : {
5720 5363 : ImplDrawText( *pSalLayout );
5721 5363 : pSalLayout->Release();
5722 : }
5723 :
5724 5400 : if( mpAlphaVDev )
5725 0 : mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
5726 : }
5727 :
5728 : // -----------------------------------------------------------------------
5729 :
5730 32600 : long OutputDevice::GetTextWidth( const String& rStr,
5731 : xub_StrLen nIndex, xub_StrLen nLen ) const
5732 : {
5733 : OSL_TRACE( "OutputDevice::GetTextWidth()" );
5734 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5735 :
5736 32600 : long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
5737 32600 : return nWidth;
5738 : }
5739 :
5740 : // -----------------------------------------------------------------------
5741 :
5742 47028 : long OutputDevice::GetTextHeight() const
5743 : {
5744 : OSL_TRACE( "OutputDevice::GetTextHeight()" );
5745 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5746 :
5747 47028 : if( mbNewFont )
5748 27441 : if( !ImplNewFont() )
5749 0 : return 0;
5750 47028 : if( mbInitFont )
5751 27878 : if( !ImplNewFont() )
5752 0 : return 0;
5753 :
5754 47028 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
5755 :
5756 47028 : if ( mbMap )
5757 40840 : nHeight = ImplDevicePixelToLogicHeight( nHeight );
5758 :
5759 47028 : return nHeight;
5760 : }
5761 :
5762 : // -----------------------------------------------------------------------
5763 :
5764 498 : void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
5765 : const sal_Int32* pDXAry,
5766 : xub_StrLen nIndex, xub_StrLen nLen )
5767 : {
5768 : OSL_TRACE( "OutputDevice::DrawTextArray()" );
5769 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5770 :
5771 498 : if ( mpMetaFile )
5772 11 : mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
5773 :
5774 498 : if ( !IsDeviceOutputNecessary() )
5775 11 : return;
5776 487 : if( !mpGraphics && !ImplGetGraphics() )
5777 0 : return;
5778 487 : if( mbInitClipRegion )
5779 80 : ImplInitClipRegion();
5780 487 : if( mbOutputClipped )
5781 0 : return;
5782 :
5783 487 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
5784 487 : if( pSalLayout )
5785 : {
5786 472 : ImplDrawText( *pSalLayout );
5787 472 : pSalLayout->Release();
5788 : }
5789 :
5790 487 : if( mpAlphaVDev )
5791 0 : mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
5792 : }
5793 :
5794 : // -----------------------------------------------------------------------
5795 :
5796 45664 : long OutputDevice::GetTextArray( const String& rStr, sal_Int32* pDXAry,
5797 : xub_StrLen nIndex, xub_StrLen nLen ) const
5798 : {
5799 : OSL_TRACE( "OutputDevice::GetTextArray()" );
5800 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5801 :
5802 45664 : if( nIndex >= rStr.Len() )
5803 18349 : return 0;
5804 27315 : if( (sal_uLong)nIndex+nLen >= rStr.Len() )
5805 26150 : nLen = rStr.Len() - nIndex;
5806 :
5807 : // do layout
5808 27315 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
5809 27315 : if( !pSalLayout )
5810 2 : return 0;
5811 :
5812 27313 : long nWidth = pSalLayout->FillDXArray( pDXAry );
5813 27313 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
5814 27313 : pSalLayout->Release();
5815 :
5816 : // convert virtual char widths to virtual absolute positions
5817 27313 : if( pDXAry )
5818 82845 : for( int i = 1; i < nLen; ++i )
5819 70379 : pDXAry[ i ] += pDXAry[ i-1 ];
5820 :
5821 : // convert from font units to logical units
5822 27313 : if( mbMap )
5823 : {
5824 23403 : if( pDXAry )
5825 94673 : for( int i = 0; i < nLen; ++i )
5826 82292 : pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
5827 23403 : nWidth = ImplDevicePixelToLogicWidth( nWidth );
5828 : }
5829 :
5830 27313 : if( nWidthFactor > 1 )
5831 : {
5832 0 : if( pDXAry )
5833 0 : for( int i = 0; i < nLen; ++i )
5834 0 : pDXAry[i] /= nWidthFactor;
5835 0 : nWidth /= nWidthFactor;
5836 : }
5837 :
5838 27313 : return nWidth;
5839 : }
5840 :
5841 : // -----------------------------------------------------------------------
5842 :
5843 30 : bool OutputDevice::GetCaretPositions( const XubString& rStr, sal_Int32* pCaretXArray,
5844 : xub_StrLen nIndex, xub_StrLen nLen,
5845 : sal_Int32* pDXAry, long nLayoutWidth,
5846 : sal_Bool bCellBreaking ) const
5847 : {
5848 : OSL_TRACE( "OutputDevice::GetCaretPositions()" );
5849 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5850 :
5851 30 : if( nIndex >= rStr.Len() )
5852 0 : return false;
5853 30 : if( (sal_uLong)nIndex+nLen >= rStr.Len() )
5854 30 : nLen = rStr.Len() - nIndex;
5855 :
5856 : // layout complex text
5857 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
5858 30 : Point(0,0), nLayoutWidth, pDXAry );
5859 30 : if( !pSalLayout )
5860 0 : return false;
5861 :
5862 30 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
5863 30 : pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
5864 30 : long nWidth = pSalLayout->GetTextWidth();
5865 30 : pSalLayout->Release();
5866 :
5867 : // fixup unknown caret positions
5868 : int i;
5869 30 : for( i = 0; i < 2 * nLen; ++i )
5870 30 : if( pCaretXArray[ i ] >= 0 )
5871 30 : break;
5872 30 : long nXPos = pCaretXArray[ i ];
5873 620 : for( i = 0; i < 2 * nLen; ++i )
5874 : {
5875 590 : if( pCaretXArray[ i ] >= 0 )
5876 590 : nXPos = pCaretXArray[ i ];
5877 : else
5878 0 : pCaretXArray[ i ] = nXPos;
5879 : }
5880 :
5881 : // handle window mirroring
5882 30 : if( IsRTLEnabled() )
5883 : {
5884 0 : for( i = 0; i < 2 * nLen; ++i )
5885 0 : pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
5886 : }
5887 :
5888 : // convert from font units to logical units
5889 30 : if( mbMap )
5890 : {
5891 0 : for( i = 0; i < 2*nLen; ++i )
5892 0 : pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
5893 : }
5894 :
5895 30 : if( nWidthFactor != 1 )
5896 : {
5897 0 : for( i = 0; i < 2*nLen; ++i )
5898 0 : pCaretXArray[i] /= nWidthFactor;
5899 : }
5900 :
5901 : // if requested move caret position to cell limits
5902 : if( bCellBreaking )
5903 : {
5904 : ; // TODO
5905 : }
5906 :
5907 30 : return true;
5908 : }
5909 :
5910 : // -----------------------------------------------------------------------
5911 :
5912 22255 : void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
5913 : const String& rStr,
5914 : xub_StrLen nIndex, xub_StrLen nLen )
5915 : {
5916 : OSL_TRACE( "OutputDevice::DrawStretchText()" );
5917 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5918 :
5919 22255 : if ( mpMetaFile )
5920 20768 : mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
5921 :
5922 22255 : if ( !IsDeviceOutputNecessary() )
5923 43023 : return;
5924 :
5925 1487 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, nWidth, NULL, true );
5926 1487 : if( pSalLayout )
5927 : {
5928 1487 : ImplDrawText( *pSalLayout );
5929 1487 : pSalLayout->Release();
5930 : }
5931 :
5932 1487 : if( mpAlphaVDev )
5933 0 : mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
5934 : }
5935 :
5936 : // -----------------------------------------------------------------------
5937 :
5938 52016 : ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( String& rStr,
5939 : xub_StrLen nMinIndex, xub_StrLen nLen,
5940 : long nPixelWidth, const sal_Int32* pDXArray ) const
5941 : {
5942 : // get string length for calculating extents
5943 52016 : xub_StrLen nEndIndex = rStr.Len();
5944 52016 : if( (sal_uLong)nMinIndex + nLen < nEndIndex )
5945 1372 : nEndIndex = nMinIndex + nLen;
5946 :
5947 : // don't bother if there is nothing to do
5948 52016 : if( nEndIndex < nMinIndex )
5949 0 : nEndIndex = nMinIndex;
5950 :
5951 52016 : int nLayoutFlags = 0;
5952 52016 : if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
5953 7 : nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
5954 52016 : if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
5955 13483 : nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
5956 38533 : else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
5957 : {
5958 : // disable Bidi if no RTL hint and no RTL codes used
5959 38533 : const sal_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
5960 38533 : const sal_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
5961 143421 : for( ; pStr < pEnd; ++pStr )
5962 104889 : if( ((*pStr >= 0x0580) && (*pStr < 0x0800)) // middle eastern scripts
5963 : || ((*pStr >= 0xFB18) && (*pStr < 0xFE00)) // hebrew + arabic A presentation forms
5964 : || ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
5965 1 : break;
5966 38533 : if( pStr >= pEnd )
5967 38532 : nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
5968 : }
5969 :
5970 52016 : if( mbKerning )
5971 903 : nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
5972 52016 : if( maFont.GetKerning() & KERNING_ASIAN )
5973 0 : nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
5974 52016 : if( maFont.IsVertical() )
5975 0 : nLayoutFlags |= SAL_LAYOUT_VERTICAL;
5976 :
5977 52016 : if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
5978 0 : nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
5979 52016 : else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
5980 11583 : nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
5981 : else
5982 : {
5983 : // disable CTL for non-CTL text
5984 40433 : const sal_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
5985 40433 : const sal_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
5986 190407 : for( ; pStr < pEnd; ++pStr )
5987 150458 : if( ((*pStr >= 0x0300) && (*pStr < 0x0370)) // diacritical marks
5988 : || ((*pStr >= 0x0590) && (*pStr < 0x10A0)) // many CTL scripts
5989 : || ((*pStr >= 0x1100) && (*pStr < 0x1200)) // hangul jamo
5990 : || ((*pStr >= 0x1700) && (*pStr < 0x1900)) // many CTL scripts
5991 : || ((*pStr >= 0xFB1D) && (*pStr < 0xFE00)) // middle east presentation
5992 : || ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation B
5993 484 : break;
5994 40433 : if( pStr >= pEnd )
5995 39949 : nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
5996 : }
5997 :
5998 52016 : if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
5999 : {
6000 : // disable character localization when no digits used
6001 29237 : const sal_Unicode* pBase = rStr.GetBuffer();
6002 29237 : const sal_Unicode* pStr = pBase + nMinIndex;
6003 29237 : const sal_Unicode* pEnd = pBase + nEndIndex;
6004 150831 : for( ; pStr < pEnd; ++pStr )
6005 : {
6006 : // TODO: are there non-digit localizations?
6007 121594 : if( (*pStr >= '0') && (*pStr <= '9') )
6008 : {
6009 : // translate characters to local preference
6010 11676 : sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
6011 11676 : if( cChar != *pStr )
6012 : // TODO: are the localized digit surrogates?
6013 : rStr.SetChar( static_cast<sal_uInt16>(pStr - pBase),
6014 0 : static_cast<sal_Unicode>(cChar) );
6015 : }
6016 : }
6017 : }
6018 :
6019 : // right align for RTL text, DRAWPOS_REVERSED, RTL window style
6020 52016 : bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
6021 52016 : if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
6022 72 : bRightAlign = false;
6023 51944 : else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
6024 0 : bRightAlign = true;
6025 : // SSA: hack for western office, ie text get right aligned
6026 : // for debugging purposes of mirrored UI
6027 : //static const char* pEnv = getenv( "SAL_RTL_MIRRORTEXT" );
6028 52016 : bool bRTLWindow = IsRTLEnabled();
6029 52016 : bRightAlign ^= bRTLWindow;
6030 52016 : if( bRightAlign )
6031 7 : nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
6032 :
6033 : // set layout options
6034 52016 : ImplLayoutArgs aLayoutArgs( rStr.GetBuffer(), rStr.Len(), nMinIndex, nEndIndex, nLayoutFlags );
6035 :
6036 52016 : int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
6037 52016 : aLayoutArgs.SetOrientation( nOrientation );
6038 :
6039 52016 : aLayoutArgs.SetLayoutWidth( nPixelWidth );
6040 52016 : aLayoutArgs.SetDXArray( pDXArray );
6041 :
6042 52016 : return aLayoutArgs;
6043 : }
6044 :
6045 : // -----------------------------------------------------------------------
6046 :
6047 52034 : SalLayout* OutputDevice::ImplLayout( const String& rOrigStr,
6048 : xub_StrLen nMinIndex,
6049 : xub_StrLen nLen,
6050 : const Point& rLogicalPos,
6051 : long nLogicalWidth,
6052 : const sal_Int32* pDXArray,
6053 : bool bFilter ) const
6054 : {
6055 : // we need a graphics
6056 52034 : if( !mpGraphics )
6057 2 : if( !ImplGetGraphics() )
6058 2 : return NULL;
6059 :
6060 : // initialize font if needed
6061 52032 : if( mbNewFont )
6062 10039 : if( !ImplNewFont() )
6063 0 : return NULL;
6064 52032 : if( mbInitFont )
6065 13830 : ImplInitFont();
6066 :
6067 : // check string index and length
6068 52032 : if( (unsigned)nMinIndex + nLen > rOrigStr.Len() )
6069 : {
6070 23593 : const int nNewLen = (int)rOrigStr.Len() - nMinIndex;
6071 23593 : if( nNewLen <= 0 )
6072 37 : return NULL;
6073 23556 : nLen = static_cast<xub_StrLen>(nNewLen);
6074 : }
6075 :
6076 51995 : String aStr = rOrigStr;
6077 :
6078 : // filter out special markers
6079 51995 : if( bFilter )
6080 : {
6081 7337 : xub_StrLen nCutStart, nCutStop, nOrgLen = nLen;
6082 7337 : rtl::OUString aTmpStr(aStr);
6083 7337 : bool bFiltered = mpGraphics->filterText( rOrigStr, aTmpStr, nMinIndex, nLen, nCutStart, nCutStop );
6084 7337 : aStr = aTmpStr;
6085 7337 : if( !nLen )
6086 15 : return NULL;
6087 :
6088 7322 : if( bFiltered && nCutStop != nCutStart && pDXArray )
6089 : {
6090 0 : if( !nLen )
6091 0 : pDXArray = NULL;
6092 : else
6093 : {
6094 0 : sal_Int32* pAry = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
6095 0 : if( nCutStart > nMinIndex )
6096 0 : memcpy( pAry, pDXArray, sizeof(sal_Int32)*(nCutStart-nMinIndex) );
6097 : // note: nCutStart will never be smaller than nMinIndex
6098 0 : memcpy( pAry+nCutStart-nMinIndex,
6099 0 : pDXArray + nOrgLen - (nCutStop-nMinIndex),
6100 0 : sizeof(sal_Int32)*(nLen - (nCutStart-nMinIndex)) );
6101 0 : pDXArray = pAry;
6102 : }
6103 7337 : }
6104 : }
6105 :
6106 : // convert from logical units to physical units
6107 : // recode string if needed
6108 51980 : if( mpFontEntry->mpConversion )
6109 0 : mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.Len() );
6110 :
6111 51980 : long nPixelWidth = nLogicalWidth;
6112 51980 : if( nLogicalWidth && mbMap )
6113 1432 : nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
6114 51980 : if( pDXArray && mbMap )
6115 : {
6116 : // convert from logical units to font units using a temporary array
6117 464 : sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
6118 : // using base position for better rounding a.k.a. "dancing characters"
6119 464 : int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
6120 7255 : for( int i = 0; i < nLen; ++i )
6121 6791 : pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
6122 :
6123 464 : pDXArray = pTempDXAry;
6124 : }
6125 :
6126 51980 : ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
6127 :
6128 : // get matching layout object for base font
6129 51980 : SalLayout* pSalLayout = NULL;
6130 51980 : if( mpPDFWriter )
6131 0 : pSalLayout = mpPDFWriter->GetTextLayout( aLayoutArgs, &mpFontEntry->maFontSelData );
6132 :
6133 51980 : if( !pSalLayout )
6134 51980 : pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
6135 :
6136 : // layout text
6137 51980 : if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
6138 : {
6139 0 : pSalLayout->Release();
6140 0 : pSalLayout = NULL;
6141 : }
6142 :
6143 51980 : if( !pSalLayout )
6144 0 : return NULL;
6145 :
6146 : // do glyph fallback if needed
6147 : // #105768# avoid fallback for very small font sizes
6148 51980 : if( aLayoutArgs.NeedFallback() )
6149 3264 : if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) )
6150 3264 : pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs );
6151 :
6152 : // position, justify, etc. the layout
6153 51980 : pSalLayout->AdjustLayout( aLayoutArgs );
6154 51980 : pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
6155 : // adjust to right alignment if necessary
6156 51980 : if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
6157 : {
6158 : long nRTLOffset;
6159 7 : if( pDXArray )
6160 2 : nRTLOffset = pDXArray[ nLen - 1 ];
6161 5 : else if( nPixelWidth )
6162 0 : nRTLOffset = nPixelWidth;
6163 : else
6164 5 : nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
6165 7 : pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
6166 : }
6167 :
6168 51980 : return pSalLayout;
6169 : }
6170 :
6171 3264 : SalLayout* OutputDevice::getFallbackFontThatFits(ImplFontEntry &rFallbackFont,
6172 : FontSelectPattern &rFontSelData, int nFallbackLevel,
6173 : ImplLayoutArgs& rLayoutArgs, const ImplFontMetricData& rOrigMetric) const
6174 : {
6175 3264 : rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
6176 :
6177 3264 : rLayoutArgs.ResetPos();
6178 3264 : SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
6179 :
6180 3264 : if (!pFallback)
6181 0 : return NULL;
6182 :
6183 3264 : if (!pFallback->LayoutText(rLayoutArgs))
6184 : {
6185 : // there is no need for a font that couldn't resolve anything
6186 0 : pFallback->Release();
6187 0 : return NULL;
6188 : }
6189 :
6190 3264 : Rectangle aBoundRect;
6191 3264 : bool bHaveBounding = false;
6192 3264 : Rectangle aRectangle;
6193 :
6194 3264 : pFallback->AdjustLayout( rLayoutArgs );
6195 :
6196 : //All we care about here is getting the vertical bounds of this text and
6197 : //make sure it will fit inside the available space
6198 3264 : Point aPos;
6199 6683 : for( int nStart = 0;;)
6200 : {
6201 : sal_GlyphId nLGlyph;
6202 6683 : if( !pFallback->GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
6203 : break;
6204 :
6205 3419 : sal_GlyphId nFontTag = nFallbackLevel << GF_FONTSHIFT;
6206 3419 : nLGlyph |= nFontTag;
6207 :
6208 : // get bounding rectangle of individual glyph
6209 3419 : if( mpGraphics->GetGlyphBoundRect( nLGlyph, aRectangle ) )
6210 : {
6211 : // merge rectangle
6212 3419 : aRectangle += aPos;
6213 3419 : aBoundRect.Union( aRectangle );
6214 3419 : bHaveBounding = true;
6215 : }
6216 : }
6217 :
6218 : //Shrink it down if it won't fit
6219 3264 : if (bHaveBounding)
6220 : {
6221 3264 : long nGlyphsAscent = -aBoundRect.Top();
6222 : float fScaleTop = nGlyphsAscent > rOrigMetric.mnAscent ?
6223 3264 : rOrigMetric.mnAscent/(float)nGlyphsAscent : 1;
6224 3264 : long nGlyphsDescent = aBoundRect.Bottom();
6225 : float fScaleBottom = nGlyphsDescent > rOrigMetric.mnDescent ?
6226 3264 : rOrigMetric.mnDescent/(float)nGlyphsDescent : 1;
6227 3264 : float fScale = fScaleBottom < fScaleTop ? fScaleBottom : fScaleTop;
6228 3264 : if (fScale < 1)
6229 : {
6230 1154 : long nOrigHeight = rFontSelData.mnHeight;
6231 1154 : long nNewHeight = static_cast<int>(static_cast<float>(rFontSelData.mnHeight) * fScale);
6232 :
6233 1154 : if (nNewHeight == nOrigHeight)
6234 0 : --nNewHeight;
6235 :
6236 1154 : pFallback->Release();
6237 :
6238 1154 : rFontSelData.mnHeight = nNewHeight;
6239 1154 : rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
6240 1154 : rFontSelData.mnHeight = nOrigHeight;
6241 :
6242 1154 : rLayoutArgs.ResetPos();
6243 1154 : pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
6244 1154 : if (pFallback && !pFallback->LayoutText(rLayoutArgs))
6245 : {
6246 0 : pFallback->Release();
6247 0 : pFallback = NULL;
6248 : }
6249 : SAL_WARN_IF(pFallback, "vcl.gdi", "we couldn't layout text with a smaller point size that worked with a bigger one");
6250 : }
6251 : }
6252 3264 : return pFallback;
6253 : }
6254 :
6255 : // -----------------------------------------------------------------------
6256 :
6257 3264 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
6258 : {
6259 : // prepare multi level glyph fallback
6260 3264 : MultiSalLayout* pMultiSalLayout = NULL;
6261 3264 : ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
6262 3264 : rLayoutArgs.PrepareFallback();
6263 3264 : rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
6264 :
6265 : // get list of unicodes that need glyph fallback
6266 3264 : int nCharPos = -1;
6267 3264 : bool bRTL = false;
6268 3264 : rtl::OUStringBuffer aMissingCodeBuf;
6269 9947 : while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
6270 3419 : aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
6271 3264 : rLayoutArgs.ResetPos();
6272 3264 : rtl::OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
6273 :
6274 3264 : FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
6275 :
6276 3264 : ImplFontMetricData aOrigMetric( aFontSelData );
6277 : // TODO: use cached metric in fontentry
6278 3264 : mpGraphics->GetFontMetric( &aOrigMetric );
6279 :
6280 : // when device specific font substitution may have been performed for
6281 : // the originally selected font then make sure that a fallback to that
6282 : // font is performed first
6283 3264 : int nDevSpecificFallback = 0;
6284 3264 : if( mpOutDevData && !mpOutDevData->maDevFontSubst.Empty() )
6285 0 : nDevSpecificFallback = 1;
6286 :
6287 : // try if fallback fonts support the missing unicodes
6288 3264 : for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
6289 : {
6290 : // find a font family suited for glyph fallback
6291 : #ifndef FONTFALLBACK_HOOKS_DISABLED
6292 : // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
6293 : // if the system-specific glyph fallback is active
6294 3264 : aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
6295 : #endif
6296 : ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontList,
6297 3264 : aFontSelData, nFallbackLevel-nDevSpecificFallback, aMissingCodes );
6298 3264 : if( !pFallbackFont )
6299 0 : break;
6300 :
6301 3264 : aFontSelData.mpFontEntry = pFallbackFont;
6302 3264 : aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
6303 3264 : if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
6304 : {
6305 : // ignore fallback font if it is the same as the original font
6306 3264 : if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
6307 : {
6308 0 : mpFontCache->Release( pFallbackFont );
6309 0 : continue;
6310 : }
6311 : }
6312 :
6313 : // create and add glyph fallback layout to multilayout
6314 : SalLayout* pFallback = getFallbackFontThatFits(*pFallbackFont, aFontSelData,
6315 3264 : nFallbackLevel, rLayoutArgs, aOrigMetric);
6316 3264 : if (pFallback)
6317 : {
6318 3264 : if( !pMultiSalLayout )
6319 3264 : pMultiSalLayout = new MultiSalLayout( *pSalLayout );
6320 : pMultiSalLayout->AddFallback( *pFallback,
6321 3264 : rLayoutArgs.maRuns, aFontSelData.mpFontData );
6322 3264 : if (nFallbackLevel == MAX_FALLBACK-1)
6323 0 : pMultiSalLayout->SetInComplete();
6324 : }
6325 :
6326 3264 : mpFontCache->Release( pFallbackFont );
6327 :
6328 : // break when this fallback was sufficient
6329 3264 : if( !rLayoutArgs.PrepareFallback() )
6330 3264 : break;
6331 : }
6332 :
6333 3264 : if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
6334 3264 : pSalLayout = pMultiSalLayout;
6335 :
6336 : // restore orig font settings
6337 3264 : pSalLayout->InitFont();
6338 3264 : rLayoutArgs.maRuns = aLayoutRuns;
6339 :
6340 3264 : return pSalLayout;
6341 : }
6342 :
6343 : // -----------------------------------------------------------------------
6344 :
6345 1 : sal_Bool OutputDevice::GetTextIsRTL(
6346 : const String& rString,
6347 : xub_StrLen nIndex, xub_StrLen nLen ) const
6348 : {
6349 1 : String aStr( rString );
6350 1 : ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
6351 1 : bool bRTL = false;
6352 1 : int nCharPos = -1;
6353 1 : aArgs.GetNextPos( &nCharPos, &bRTL );
6354 1 : return (nCharPos != nIndex) ? sal_True : sal_False;
6355 : }
6356 :
6357 : // -----------------------------------------------------------------------
6358 :
6359 101 : xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
6360 : xub_StrLen nIndex, xub_StrLen nLen,
6361 : long nCharExtra, sal_Bool /*TODO: bCellBreaking*/ ) const
6362 : {
6363 : OSL_TRACE( "OutputDevice::GetTextBreak()" );
6364 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6365 :
6366 101 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
6367 101 : xub_StrLen nRetVal = STRING_LEN;
6368 101 : if( pSalLayout )
6369 : {
6370 : // convert logical widths into layout units
6371 : // NOTE: be very careful to avoid rounding errors for nCharExtra case
6372 : // problem with rounding errors especially for small nCharExtras
6373 : // TODO: remove when layout units have subpixel granularity
6374 101 : long nWidthFactor = pSalLayout->GetUnitsPerPixel();
6375 101 : long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
6376 101 : nTextWidth *= nWidthFactor * nSubPixelFactor;
6377 101 : long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
6378 101 : long nExtraPixelWidth = 0;
6379 101 : if( nCharExtra != 0 )
6380 : {
6381 0 : nCharExtra *= nWidthFactor * nSubPixelFactor;
6382 0 : nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
6383 : }
6384 101 : nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6385 :
6386 101 : pSalLayout->Release();
6387 : }
6388 :
6389 101 : return nRetVal;
6390 : }
6391 :
6392 : // -----------------------------------------------------------------------
6393 :
6394 0 : xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
6395 : sal_Unicode nHyphenatorChar, xub_StrLen& rHyphenatorPos,
6396 : xub_StrLen nIndex, xub_StrLen nLen,
6397 : long nCharExtra ) const
6398 : {
6399 : OSL_TRACE( "OutputDevice::GetTextBreak()" );
6400 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6401 :
6402 0 : rHyphenatorPos = STRING_LEN;
6403 :
6404 0 : SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
6405 0 : if( !pSalLayout )
6406 0 : return STRING_LEN;
6407 :
6408 : // convert logical widths into layout units
6409 : // NOTE: be very careful to avoid rounding errors for nCharExtra case
6410 : // problem with rounding errors especially for small nCharExtras
6411 : // TODO: remove when layout units have subpixel granularity
6412 0 : long nWidthFactor = pSalLayout->GetUnitsPerPixel();
6413 0 : long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
6414 :
6415 0 : nTextWidth *= nWidthFactor * nSubPixelFactor;
6416 0 : long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
6417 0 : long nExtraPixelWidth = 0;
6418 0 : if( nCharExtra != 0 )
6419 : {
6420 0 : nCharExtra *= nWidthFactor * nSubPixelFactor;
6421 0 : nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
6422 : }
6423 :
6424 : // calculate un-hyphenated break position
6425 0 : xub_StrLen nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6426 :
6427 : // calculate hyphenated break position
6428 0 : rtl::OUString aHyphenatorStr(nHyphenatorChar);
6429 0 : xub_StrLen nTempLen = 1;
6430 0 : SalLayout* pHyphenatorLayout = ImplLayout( aHyphenatorStr, 0, nTempLen );
6431 0 : if( pHyphenatorLayout )
6432 : {
6433 : // calculate subpixel width of hyphenation character
6434 0 : long nHyphenatorPixelWidth = pHyphenatorLayout->GetTextWidth() * nSubPixelFactor;
6435 0 : pHyphenatorLayout->Release();
6436 :
6437 : // calculate hyphenated break position
6438 0 : nTextPixelWidth -= nHyphenatorPixelWidth;
6439 0 : if( nExtraPixelWidth > 0 )
6440 0 : nTextPixelWidth -= nExtraPixelWidth;
6441 :
6442 0 : rHyphenatorPos = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6443 :
6444 0 : if( rHyphenatorPos > nRetVal )
6445 0 : rHyphenatorPos = nRetVal;
6446 : }
6447 :
6448 0 : pSalLayout->Release();
6449 0 : return nRetVal;
6450 : }
6451 :
6452 : // -----------------------------------------------------------------------
6453 :
6454 0 : void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
6455 : const String& rOrigStr, sal_uInt16 nStyle,
6456 : MetricVector* pVector, String* pDisplayText,
6457 : ::vcl::ITextLayout& _rLayout )
6458 : {
6459 0 : Color aOldTextColor;
6460 0 : Color aOldTextFillColor;
6461 0 : sal_Bool bRestoreFillColor = false;
6462 0 : if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
6463 : {
6464 0 : sal_Bool bHighContrastBlack = sal_False;
6465 0 : sal_Bool bHighContrastWhite = sal_False;
6466 0 : const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
6467 0 : if( rStyleSettings.GetHighContrastMode() )
6468 : {
6469 0 : Color aCol;
6470 0 : if( rTargetDevice.IsBackground() )
6471 0 : aCol = rTargetDevice.GetBackground().GetColor();
6472 : else
6473 : // best guess is the face color here
6474 : // but it may be totally wrong. the background color
6475 : // was typically already reset
6476 0 : aCol = rStyleSettings.GetFaceColor();
6477 :
6478 0 : bHighContrastBlack = aCol.IsDark();
6479 0 : bHighContrastWhite = aCol.IsBright();
6480 : }
6481 :
6482 0 : aOldTextColor = rTargetDevice.GetTextColor();
6483 0 : if ( rTargetDevice.IsTextFillColor() )
6484 : {
6485 0 : bRestoreFillColor = sal_True;
6486 0 : aOldTextFillColor = rTargetDevice.GetTextFillColor();
6487 : }
6488 0 : if( bHighContrastBlack )
6489 0 : rTargetDevice.SetTextColor( COL_GREEN );
6490 0 : else if( bHighContrastWhite )
6491 0 : rTargetDevice.SetTextColor( COL_LIGHTGREEN );
6492 : else
6493 : {
6494 : // draw disabled text always without shadow
6495 : // as it fits better with native look
6496 : /*
6497 : SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
6498 : Rectangle aRect = rRect;
6499 : aRect.Move( 1, 1 );
6500 : DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
6501 : */
6502 0 : rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
6503 : }
6504 : }
6505 :
6506 0 : long nWidth = rRect.GetWidth();
6507 0 : long nHeight = rRect.GetHeight();
6508 :
6509 0 : if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
6510 0 : return;
6511 :
6512 0 : Point aPos = rRect.TopLeft();
6513 :
6514 0 : long nTextHeight = rTargetDevice.GetTextHeight();
6515 0 : TextAlign eAlign = rTargetDevice.GetTextAlign();
6516 0 : xub_StrLen nMnemonicPos = STRING_NOTFOUND;
6517 :
6518 0 : String aStr = rOrigStr;
6519 0 : if ( nStyle & TEXT_DRAW_MNEMONIC )
6520 0 : aStr = GetNonMnemonicString( aStr, nMnemonicPos );
6521 :
6522 0 : const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
6523 :
6524 : // Mehrzeiligen Text behandeln wir anders
6525 0 : if ( nStyle & TEXT_DRAW_MULTILINE )
6526 : {
6527 :
6528 0 : XubString aLastLine;
6529 0 : ImplMultiTextLineInfo aMultiLineInfo;
6530 : ImplTextLineInfo* pLineInfo;
6531 : xub_StrLen i;
6532 : xub_StrLen nLines;
6533 : xub_StrLen nFormatLines;
6534 :
6535 0 : if ( nTextHeight )
6536 : {
6537 0 : long nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
6538 0 : nLines = (xub_StrLen)(nHeight/nTextHeight);
6539 0 : nFormatLines = aMultiLineInfo.Count();
6540 0 : if ( !nLines )
6541 0 : nLines = 1;
6542 0 : if ( nFormatLines > nLines )
6543 : {
6544 0 : if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
6545 : {
6546 : // Letzte Zeile zusammenbauen und kuerzen
6547 0 : nFormatLines = nLines-1;
6548 :
6549 0 : pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
6550 0 : aLastLine = convertLineEnd(aStr.Copy(pLineInfo->GetIndex()), LINEEND_LF);
6551 : // Alle LineFeed's durch Spaces ersetzen
6552 0 : xub_StrLen nLastLineLen = aLastLine.Len();
6553 0 : for ( i = 0; i < nLastLineLen; i++ )
6554 : {
6555 0 : if ( aLastLine.GetChar( i ) == _LF )
6556 0 : aLastLine.SetChar( i, ' ' );
6557 : }
6558 0 : aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
6559 0 : nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
6560 0 : nStyle |= TEXT_DRAW_TOP;
6561 : }
6562 : }
6563 : else
6564 : {
6565 0 : if ( nMaxTextWidth <= nWidth )
6566 0 : nStyle &= ~TEXT_DRAW_CLIP;
6567 : }
6568 :
6569 : // Muss in der Hoehe geclippt werden?
6570 0 : if ( nFormatLines*nTextHeight > nHeight )
6571 0 : nStyle |= TEXT_DRAW_CLIP;
6572 :
6573 : // Clipping setzen
6574 0 : if ( nStyle & TEXT_DRAW_CLIP )
6575 : {
6576 0 : rTargetDevice.Push( PUSH_CLIPREGION );
6577 0 : rTargetDevice.IntersectClipRegion( rRect );
6578 : }
6579 :
6580 : // Vertikales Alignment
6581 0 : if ( nStyle & TEXT_DRAW_BOTTOM )
6582 0 : aPos.Y() += nHeight-(nFormatLines*nTextHeight);
6583 0 : else if ( nStyle & TEXT_DRAW_VCENTER )
6584 0 : aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
6585 :
6586 : // Font Alignment
6587 0 : if ( eAlign == ALIGN_BOTTOM )
6588 0 : aPos.Y() += nTextHeight;
6589 0 : else if ( eAlign == ALIGN_BASELINE )
6590 0 : aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
6591 :
6592 : // Alle Zeilen ausgeben, bis auf die letzte
6593 0 : for ( i = 0; i < nFormatLines; i++ )
6594 : {
6595 0 : pLineInfo = aMultiLineInfo.GetLine( i );
6596 0 : if ( nStyle & TEXT_DRAW_RIGHT )
6597 0 : aPos.X() += nWidth-pLineInfo->GetWidth();
6598 0 : else if ( nStyle & TEXT_DRAW_CENTER )
6599 0 : aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
6600 0 : xub_StrLen nIndex = pLineInfo->GetIndex();
6601 0 : xub_StrLen nLineLen = pLineInfo->GetLen();
6602 0 : _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
6603 0 : if ( bDrawMnemonics )
6604 : {
6605 0 : if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
6606 : {
6607 : long nMnemonicX;
6608 : long nMnemonicY;
6609 : long nMnemonicWidth;
6610 :
6611 0 : sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
6612 : /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
6613 0 : nIndex, nLineLen );
6614 0 : long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
6615 0 : long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
6616 0 : nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
6617 :
6618 0 : Point aTempPos = rTargetDevice.LogicToPixel( aPos );
6619 0 : nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
6620 0 : nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
6621 0 : rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6622 : }
6623 : }
6624 0 : aPos.Y() += nTextHeight;
6625 0 : aPos.X() = rRect.Left();
6626 : }
6627 :
6628 :
6629 : // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
6630 : // da die Zeile gekuerzt wurde
6631 0 : if ( aLastLine.Len() )
6632 0 : _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
6633 :
6634 : // Clipping zuruecksetzen
6635 0 : if ( nStyle & TEXT_DRAW_CLIP )
6636 0 : rTargetDevice.Pop();
6637 0 : }
6638 : }
6639 : else
6640 : {
6641 0 : long nTextWidth = _rLayout.GetTextWidth( aStr, 0, STRING_LEN );
6642 :
6643 : // Evt. Text kuerzen
6644 0 : if ( nTextWidth > nWidth )
6645 : {
6646 0 : if ( nStyle & TEXT_DRAW_ELLIPSIS )
6647 : {
6648 0 : aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
6649 0 : nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
6650 0 : nStyle |= TEXT_DRAW_LEFT;
6651 0 : nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
6652 : }
6653 : }
6654 : else
6655 : {
6656 0 : if ( nTextHeight <= nHeight )
6657 0 : nStyle &= ~TEXT_DRAW_CLIP;
6658 : }
6659 :
6660 : // horizontal text alignment
6661 0 : if ( nStyle & TEXT_DRAW_RIGHT )
6662 0 : aPos.X() += nWidth-nTextWidth;
6663 0 : else if ( nStyle & TEXT_DRAW_CENTER )
6664 0 : aPos.X() += (nWidth-nTextWidth)/2;
6665 :
6666 : // vertical font alignment
6667 0 : if ( eAlign == ALIGN_BOTTOM )
6668 0 : aPos.Y() += nTextHeight;
6669 0 : else if ( eAlign == ALIGN_BASELINE )
6670 0 : aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
6671 :
6672 0 : if ( nStyle & TEXT_DRAW_BOTTOM )
6673 0 : aPos.Y() += nHeight-nTextHeight;
6674 0 : else if ( nStyle & TEXT_DRAW_VCENTER )
6675 0 : aPos.Y() += (nHeight-nTextHeight)/2;
6676 :
6677 0 : long nMnemonicX = 0;
6678 0 : long nMnemonicY = 0;
6679 0 : long nMnemonicWidth = 0;
6680 0 : if ( nMnemonicPos != STRING_NOTFOUND )
6681 : {
6682 0 : sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
6683 0 : /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
6684 0 : long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
6685 0 : long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
6686 0 : nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
6687 :
6688 0 : Point aTempPos = rTargetDevice.LogicToPixel( aPos );
6689 0 : nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
6690 0 : nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
6691 : }
6692 :
6693 0 : if ( nStyle & TEXT_DRAW_CLIP )
6694 : {
6695 0 : rTargetDevice.Push( PUSH_CLIPREGION );
6696 0 : rTargetDevice.IntersectClipRegion( rRect );
6697 0 : _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
6698 0 : if ( bDrawMnemonics )
6699 : {
6700 0 : if ( nMnemonicPos != STRING_NOTFOUND )
6701 0 : rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6702 : }
6703 0 : rTargetDevice.Pop();
6704 : }
6705 : else
6706 : {
6707 0 : _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
6708 0 : if ( bDrawMnemonics )
6709 : {
6710 0 : if ( nMnemonicPos != STRING_NOTFOUND )
6711 0 : rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6712 : }
6713 : }
6714 : }
6715 :
6716 0 : if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
6717 : {
6718 0 : rTargetDevice.SetTextColor( aOldTextColor );
6719 0 : if ( bRestoreFillColor )
6720 0 : rTargetDevice.SetTextFillColor( aOldTextFillColor );
6721 0 : }
6722 : }
6723 :
6724 : // -----------------------------------------------------------------------
6725 :
6726 0 : void OutputDevice::AddTextRectActions( const Rectangle& rRect,
6727 : const String& rOrigStr,
6728 : sal_uInt16 nStyle,
6729 : GDIMetaFile& rMtf )
6730 : {
6731 : OSL_TRACE( "OutputDevice::AddTextRectActions( const Rectangle& )" );
6732 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6733 :
6734 0 : if ( !rOrigStr.Len() || rRect.IsEmpty() )
6735 : return;
6736 :
6737 : // we need a graphics
6738 0 : if( !mpGraphics && !ImplGetGraphics() )
6739 : return;
6740 0 : if( mbInitClipRegion )
6741 0 : ImplInitClipRegion();
6742 :
6743 : // temporarily swap in passed mtf for action generation, and
6744 : // disable output generation.
6745 0 : const sal_Bool bOutputEnabled( IsOutputEnabled() );
6746 0 : GDIMetaFile* pMtf = mpMetaFile;
6747 :
6748 0 : mpMetaFile = &rMtf;
6749 0 : EnableOutput( sal_False );
6750 :
6751 : // #i47157# Factored out to ImplDrawTextRect(), to be shared
6752 : // between us and DrawText()
6753 0 : DefaultTextLayout aLayout( *this );
6754 0 : ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
6755 :
6756 : // and restore again
6757 0 : EnableOutput( bOutputEnabled );
6758 0 : mpMetaFile = pMtf;
6759 : }
6760 :
6761 : // -----------------------------------------------------------------------
6762 :
6763 0 : void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle,
6764 : MetricVector* pVector, String* pDisplayText,
6765 : ::vcl::ITextLayout* _pTextLayout )
6766 : {
6767 0 : if( mpOutDevData && mpOutDevData->mpRecordLayout )
6768 : {
6769 0 : pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
6770 0 : pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
6771 : }
6772 :
6773 : OSL_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
6774 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6775 :
6776 0 : bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
6777 0 : if ( mpMetaFile && !bDecomposeTextRectAction )
6778 0 : mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
6779 :
6780 0 : if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
6781 : return;
6782 :
6783 : // we need a graphics
6784 0 : if( !mpGraphics && !ImplGetGraphics() )
6785 : return;
6786 0 : if( mbInitClipRegion )
6787 0 : ImplInitClipRegion();
6788 0 : if( mbOutputClipped && !bDecomposeTextRectAction )
6789 : return;
6790 :
6791 : // temporarily disable mtf action generation (ImplDrawText _does_
6792 : // create META_TEXT_ACTIONs otherwise)
6793 0 : GDIMetaFile* pMtf = mpMetaFile;
6794 0 : if ( !bDecomposeTextRectAction )
6795 0 : mpMetaFile = NULL;
6796 :
6797 : // #i47157# Factored out to ImplDrawText(), to be used also
6798 : // from AddTextRectActions()
6799 0 : DefaultTextLayout aDefaultLayout( *this );
6800 0 : ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
6801 :
6802 : // and enable again
6803 0 : mpMetaFile = pMtf;
6804 :
6805 0 : if( mpAlphaVDev )
6806 0 : mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
6807 : }
6808 :
6809 : // -----------------------------------------------------------------------
6810 :
6811 0 : Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
6812 : const XubString& rStr, sal_uInt16 nStyle,
6813 : TextRectInfo* pInfo,
6814 : const ::vcl::ITextLayout* _pTextLayout ) const
6815 : {
6816 : OSL_TRACE( "OutputDevice::GetTextRect()" );
6817 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6818 :
6819 0 : Rectangle aRect = rRect;
6820 : xub_StrLen nLines;
6821 0 : long nWidth = rRect.GetWidth();
6822 : long nMaxWidth;
6823 0 : long nTextHeight = GetTextHeight();
6824 :
6825 0 : String aStr = rStr;
6826 0 : if ( nStyle & TEXT_DRAW_MNEMONIC )
6827 0 : aStr = GetNonMnemonicString( aStr );
6828 :
6829 0 : if ( nStyle & TEXT_DRAW_MULTILINE )
6830 : {
6831 0 : ImplMultiTextLineInfo aMultiLineInfo;
6832 : ImplTextLineInfo* pLineInfo;
6833 : xub_StrLen nFormatLines;
6834 : xub_StrLen i;
6835 :
6836 0 : nMaxWidth = 0;
6837 0 : DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
6838 0 : ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
6839 0 : nFormatLines = aMultiLineInfo.Count();
6840 0 : if ( !nTextHeight )
6841 0 : nTextHeight = 1;
6842 0 : nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
6843 0 : if ( pInfo )
6844 0 : pInfo->mnLineCount = nFormatLines;
6845 0 : if ( !nLines )
6846 0 : nLines = 1;
6847 0 : if ( nFormatLines <= nLines )
6848 0 : nLines = nFormatLines;
6849 : else
6850 : {
6851 0 : if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
6852 0 : nLines = nFormatLines;
6853 : else
6854 : {
6855 0 : if ( pInfo )
6856 0 : pInfo->mbEllipsis = sal_True;
6857 0 : nMaxWidth = nWidth;
6858 : }
6859 : }
6860 0 : if ( pInfo )
6861 : {
6862 0 : sal_Bool bMaxWidth = nMaxWidth == 0;
6863 0 : pInfo->mnMaxWidth = 0;
6864 0 : for ( i = 0; i < nLines; i++ )
6865 : {
6866 0 : pLineInfo = aMultiLineInfo.GetLine( i );
6867 0 : if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
6868 0 : nMaxWidth = pLineInfo->GetWidth();
6869 0 : if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
6870 0 : pInfo->mnMaxWidth = pLineInfo->GetWidth();
6871 : }
6872 : }
6873 0 : else if ( !nMaxWidth )
6874 : {
6875 0 : for ( i = 0; i < nLines; i++ )
6876 : {
6877 0 : pLineInfo = aMultiLineInfo.GetLine( i );
6878 0 : if ( pLineInfo->GetWidth() > nMaxWidth )
6879 0 : nMaxWidth = pLineInfo->GetWidth();
6880 : }
6881 0 : }
6882 : }
6883 : else
6884 : {
6885 0 : nLines = 1;
6886 0 : nMaxWidth = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
6887 :
6888 0 : if ( pInfo )
6889 : {
6890 0 : pInfo->mnLineCount = 1;
6891 0 : pInfo->mnMaxWidth = nMaxWidth;
6892 : }
6893 :
6894 0 : if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
6895 : {
6896 0 : if ( pInfo )
6897 0 : pInfo->mbEllipsis = sal_True;
6898 0 : nMaxWidth = nWidth;
6899 : }
6900 : }
6901 :
6902 0 : if ( nStyle & TEXT_DRAW_RIGHT )
6903 0 : aRect.Left() = aRect.Right()-nMaxWidth+1;
6904 0 : else if ( nStyle & TEXT_DRAW_CENTER )
6905 : {
6906 0 : aRect.Left() += (nWidth-nMaxWidth)/2;
6907 0 : aRect.Right() = aRect.Left()+nMaxWidth-1;
6908 : }
6909 : else
6910 0 : aRect.Right() = aRect.Left()+nMaxWidth-1;
6911 :
6912 0 : if ( nStyle & TEXT_DRAW_BOTTOM )
6913 0 : aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
6914 0 : else if ( nStyle & TEXT_DRAW_VCENTER )
6915 : {
6916 0 : aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2;
6917 0 : aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
6918 : }
6919 : else
6920 0 : aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
6921 :
6922 : // #99188# get rid of rounding problems when using this rect later
6923 0 : if (nStyle & TEXT_DRAW_RIGHT)
6924 0 : aRect.Left()--;
6925 : else
6926 0 : aRect.Right()++;
6927 0 : return aRect;
6928 : }
6929 :
6930 : // -----------------------------------------------------------------------
6931 :
6932 0 : static sal_Bool ImplIsCharIn( sal_Unicode c, const sal_Char* pStr )
6933 : {
6934 0 : while ( *pStr )
6935 : {
6936 0 : if ( *pStr == c )
6937 0 : return sal_True;
6938 0 : pStr++;
6939 : }
6940 :
6941 0 : return sal_False;
6942 : }
6943 :
6944 : // -----------------------------------------------------------------------
6945 :
6946 0 : OUString OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
6947 : sal_uInt16 nStyle ) const
6948 : {
6949 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6950 0 : DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
6951 0 : return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
6952 : }
6953 :
6954 : // -----------------------------------------------------------------------
6955 :
6956 0 : String OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rOrigStr, long nMaxWidth,
6957 : sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
6958 : {
6959 : OSL_TRACE( "OutputDevice::ImplGetEllipsisString()" );
6960 :
6961 0 : String aStr = rOrigStr;
6962 0 : xub_StrLen nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.Len() );
6963 :
6964 :
6965 0 : if ( nIndex != STRING_LEN )
6966 : {
6967 0 : if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
6968 : {
6969 0 : String aTmpStr( aStr );
6970 0 : xub_StrLen nEraseChars = 4;
6971 0 : while( nEraseChars < aStr.Len() && _rLayout.GetTextWidth( aTmpStr, 0, aTmpStr.Len() ) > nMaxWidth )
6972 : {
6973 0 : aTmpStr = aStr;
6974 0 : xub_StrLen i = (aTmpStr.Len() - nEraseChars)/2;
6975 0 : aTmpStr.Erase( i, nEraseChars++ );
6976 0 : aTmpStr.InsertAscii( "...", i );
6977 : }
6978 0 : aStr = aTmpStr;
6979 : }
6980 0 : else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
6981 : {
6982 0 : aStr.Erase( nIndex );
6983 0 : if ( nIndex > 1 )
6984 : {
6985 0 : aStr.AppendAscii( "..." );
6986 0 : while ( aStr.Len() && (_rLayout.GetTextWidth( aStr, 0, aStr.Len() ) > nMaxWidth) )
6987 : {
6988 0 : if ( (nIndex > 1) || (nIndex == aStr.Len()) )
6989 0 : nIndex--;
6990 0 : aStr.Erase( nIndex, 1 );
6991 : }
6992 : }
6993 :
6994 0 : if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
6995 0 : aStr += rOrigStr.GetChar( 0 );
6996 : }
6997 0 : else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
6998 : {
6999 0 : rtl::OUString aPath( rOrigStr );
7000 0 : rtl::OUString aAbbreviatedPath;
7001 0 : osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
7002 0 : aStr = aAbbreviatedPath;
7003 : }
7004 0 : else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
7005 : {
7006 : static sal_Char const pSepChars[] = ".";
7007 : // Letztes Teilstueck ermitteln
7008 0 : xub_StrLen nLastContent = aStr.Len();
7009 0 : while ( nLastContent )
7010 : {
7011 0 : nLastContent--;
7012 0 : if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
7013 0 : break;
7014 : }
7015 0 : while ( nLastContent &&
7016 0 : ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
7017 0 : nLastContent--;
7018 :
7019 0 : XubString aLastStr( aStr, nLastContent, aStr.Len() );
7020 0 : XubString aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
7021 0 : aTempLastStr1 += aLastStr;
7022 0 : if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.Len() ) > nMaxWidth )
7023 0 : aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
7024 : else
7025 : {
7026 0 : sal_uInt16 nFirstContent = 0;
7027 0 : while ( nFirstContent < nLastContent )
7028 : {
7029 0 : nFirstContent++;
7030 0 : if ( ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
7031 0 : break;
7032 : }
7033 0 : while ( (nFirstContent < nLastContent) &&
7034 0 : ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
7035 0 : nFirstContent++;
7036 :
7037 0 : if ( nFirstContent >= nLastContent )
7038 0 : aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
7039 : else
7040 : {
7041 0 : if ( nFirstContent > 4 )
7042 0 : nFirstContent = 4;
7043 0 : XubString aFirstStr( aStr, 0, nFirstContent );
7044 0 : aFirstStr.AppendAscii( "..." );
7045 0 : XubString aTempStr = aFirstStr;
7046 0 : aTempStr += aLastStr;
7047 0 : if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
7048 0 : aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
7049 : else
7050 : {
7051 0 : do
7052 : {
7053 0 : aStr = aTempStr;
7054 0 : if( nLastContent > aStr.Len() )
7055 0 : nLastContent = aStr.Len();
7056 0 : while ( nFirstContent < nLastContent )
7057 : {
7058 0 : nLastContent--;
7059 0 : if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
7060 0 : break;
7061 :
7062 : }
7063 0 : while ( (nFirstContent < nLastContent) &&
7064 0 : ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
7065 0 : nLastContent--;
7066 :
7067 0 : if ( nFirstContent < nLastContent )
7068 : {
7069 0 : XubString aTempLastStr( aStr, nLastContent, aStr.Len() );
7070 0 : aTempStr = aFirstStr;
7071 0 : aTempStr += aTempLastStr;
7072 0 : if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
7073 0 : break;
7074 : }
7075 : }
7076 : while ( nFirstContent < nLastContent );
7077 0 : }
7078 : }
7079 0 : }
7080 : }
7081 : }
7082 :
7083 0 : return aStr;
7084 : }
7085 :
7086 : // -----------------------------------------------------------------------
7087 :
7088 0 : void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
7089 : xub_StrLen nIndex, xub_StrLen nLen,
7090 : sal_uInt16 nStyle, MetricVector* pVector, String* pDisplayText )
7091 : {
7092 : OSL_TRACE( "OutputDevice::DrawCtrlText()" );
7093 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7094 :
7095 0 : if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
7096 : return;
7097 :
7098 : // better get graphics here because ImplDrawMnemonicLine() will not
7099 : // we need a graphics
7100 0 : if( !mpGraphics && !ImplGetGraphics() )
7101 : return;
7102 0 : if( mbInitClipRegion )
7103 0 : ImplInitClipRegion();
7104 0 : if ( mbOutputClipped )
7105 : return;
7106 :
7107 0 : if( nIndex >= rStr.Len() )
7108 : return;
7109 0 : if( (sal_uLong)nIndex+nLen >= rStr.Len() )
7110 0 : nLen = rStr.Len() - nIndex;
7111 :
7112 0 : XubString aStr = rStr;
7113 0 : xub_StrLen nMnemonicPos = STRING_NOTFOUND;
7114 :
7115 0 : long nMnemonicX = 0;
7116 0 : long nMnemonicY = 0;
7117 0 : long nMnemonicWidth = 0;
7118 0 : if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
7119 : {
7120 0 : aStr = GetNonMnemonicString( aStr, nMnemonicPos );
7121 0 : if ( nMnemonicPos != STRING_NOTFOUND )
7122 : {
7123 0 : if( nMnemonicPos < nIndex )
7124 0 : --nIndex;
7125 0 : else if( nLen < STRING_LEN )
7126 : {
7127 0 : if( nMnemonicPos < (nIndex+nLen) )
7128 0 : --nLen;
7129 : DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
7130 : }
7131 0 : sal_Bool bInvalidPos = sal_False;
7132 :
7133 0 : if( nMnemonicPos >= nLen )
7134 : {
7135 : // #106952#
7136 : // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
7137 : // due to some strange BiDi text editors
7138 : // ->place the underline behind the string to indicate a failure
7139 0 : bInvalidPos = sal_True;
7140 0 : nMnemonicPos = nLen-1;
7141 : }
7142 :
7143 0 : sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
7144 0 : /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
7145 0 : long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
7146 0 : long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
7147 0 : nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
7148 :
7149 0 : Point aTempPos( Min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
7150 0 : if( bInvalidPos ) // #106952#, place behind the (last) character
7151 0 : aTempPos = Point( Max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
7152 :
7153 0 : aTempPos += rPos;
7154 0 : aTempPos = LogicToPixel( aTempPos );
7155 0 : nMnemonicX = mnOutOffX + aTempPos.X();
7156 0 : nMnemonicY = mnOutOffY + aTempPos.Y();
7157 : }
7158 : }
7159 :
7160 0 : if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
7161 : {
7162 0 : Color aOldTextColor;
7163 0 : Color aOldTextFillColor;
7164 : sal_Bool bRestoreFillColor;
7165 0 : sal_Bool bHighContrastBlack = sal_False;
7166 0 : sal_Bool bHighContrastWhite = sal_False;
7167 0 : const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
7168 0 : if( rStyleSettings.GetHighContrastMode() )
7169 : {
7170 0 : if( IsBackground() )
7171 : {
7172 0 : Wallpaper aWall = GetBackground();
7173 0 : Color aCol = aWall.GetColor();
7174 0 : bHighContrastBlack = aCol.IsDark();
7175 0 : bHighContrastWhite = aCol.IsBright();
7176 : }
7177 : }
7178 :
7179 0 : aOldTextColor = GetTextColor();
7180 0 : if ( IsTextFillColor() )
7181 : {
7182 0 : bRestoreFillColor = sal_True;
7183 0 : aOldTextFillColor = GetTextFillColor();
7184 : }
7185 : else
7186 0 : bRestoreFillColor = sal_False;
7187 :
7188 0 : if( bHighContrastBlack )
7189 0 : SetTextColor( COL_GREEN );
7190 0 : else if( bHighContrastWhite )
7191 0 : SetTextColor( COL_LIGHTGREEN );
7192 : else
7193 0 : SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
7194 :
7195 0 : DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
7196 0 : if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
7197 : {
7198 0 : if ( nMnemonicPos != STRING_NOTFOUND )
7199 0 : ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
7200 : }
7201 0 : SetTextColor( aOldTextColor );
7202 0 : if ( bRestoreFillColor )
7203 0 : SetTextFillColor( aOldTextFillColor );
7204 : }
7205 : else
7206 : {
7207 0 : DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
7208 0 : if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
7209 : {
7210 0 : if ( nMnemonicPos != STRING_NOTFOUND )
7211 0 : ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
7212 : }
7213 : }
7214 :
7215 0 : if( mpAlphaVDev )
7216 0 : mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
7217 : }
7218 :
7219 : // -----------------------------------------------------------------------
7220 :
7221 2360 : long OutputDevice::GetCtrlTextWidth( const String& rStr,
7222 : xub_StrLen nIndex, xub_StrLen nLen,
7223 : sal_uInt16 nStyle ) const
7224 : {
7225 : OSL_TRACE( "OutputDevice::GetCtrlTextSize()" );
7226 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7227 :
7228 2360 : if ( nStyle & TEXT_DRAW_MNEMONIC )
7229 : {
7230 : xub_StrLen nMnemonicPos;
7231 2360 : XubString aStr = GetNonMnemonicString( rStr, nMnemonicPos );
7232 2360 : if ( nMnemonicPos != STRING_NOTFOUND )
7233 : {
7234 0 : if ( nMnemonicPos < nIndex )
7235 0 : nIndex--;
7236 0 : else if ( (nLen < STRING_LEN) &&
7237 : (nMnemonicPos >= nIndex) && (nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
7238 0 : nLen--;
7239 : }
7240 2360 : return GetTextWidth( aStr, nIndex, nLen );
7241 : }
7242 : else
7243 0 : return GetTextWidth( rStr, nIndex, nLen );
7244 : }
7245 :
7246 : // -----------------------------------------------------------------------
7247 :
7248 2360 : String OutputDevice::GetNonMnemonicString( const String& rStr, xub_StrLen& rMnemonicPos )
7249 : {
7250 2360 : String aStr = rStr;
7251 2360 : xub_StrLen nLen = aStr.Len();
7252 2360 : xub_StrLen i = 0;
7253 :
7254 2360 : rMnemonicPos = STRING_NOTFOUND;
7255 50740 : while ( i < nLen )
7256 : {
7257 46020 : if ( aStr.GetChar( i ) == '~' )
7258 : {
7259 0 : if ( aStr.GetChar( i+1 ) != '~' )
7260 : {
7261 0 : if ( rMnemonicPos == STRING_NOTFOUND )
7262 0 : rMnemonicPos = i;
7263 0 : aStr.Erase( i, 1 );
7264 0 : nLen--;
7265 : }
7266 : else
7267 : {
7268 0 : aStr.Erase( i, 1 );
7269 0 : nLen--;
7270 0 : i++;
7271 : }
7272 : }
7273 : else
7274 46020 : i++;
7275 : }
7276 :
7277 2360 : return aStr;
7278 : }
7279 :
7280 : // -----------------------------------------------------------------------
7281 :
7282 50417 : int OutputDevice::GetDevFontCount() const
7283 : {
7284 : OSL_TRACE( "OutputDevice::GetDevFontCount()" );
7285 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7286 :
7287 50417 : if( !mpGetDevFontList )
7288 350 : mpGetDevFontList = mpFontList->GetDevFontList();
7289 50417 : return mpGetDevFontList->Count();
7290 : }
7291 :
7292 : // -----------------------------------------------------------------------
7293 :
7294 49940 : FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
7295 : {
7296 : OSL_TRACE( "OutputDevice::GetDevFont()" );
7297 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7298 :
7299 49940 : FontInfo aFontInfo;
7300 :
7301 49940 : ImplInitFontList();
7302 :
7303 49940 : int nCount = GetDevFontCount();
7304 49940 : if( nDevFontIndex < nCount )
7305 : {
7306 49940 : const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
7307 49940 : aFontInfo.SetName( rData.maName );
7308 49940 : aFontInfo.SetStyleName( rData.maStyleName );
7309 49940 : aFontInfo.SetCharSet( rData.mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
7310 49940 : aFontInfo.SetFamily( rData.meFamily );
7311 49940 : aFontInfo.SetPitch( rData.mePitch );
7312 49940 : aFontInfo.SetWeight( rData.meWeight );
7313 49940 : aFontInfo.SetItalic( rData.meItalic );
7314 49940 : aFontInfo.SetWidthType( rData.meWidthType );
7315 49940 : if( rData.IsScalable() )
7316 49940 : aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
7317 49940 : if( rData.mbDevice )
7318 0 : aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
7319 : }
7320 :
7321 49940 : return aFontInfo;
7322 : }
7323 :
7324 : // -----------------------------------------------------------------------
7325 :
7326 0 : sal_Bool OutputDevice::AddTempDevFont( const String& rFileURL, const String& rFontName )
7327 : {
7328 : OSL_TRACE( "OutputDevice::AddTempDevFont()" );
7329 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7330 :
7331 0 : ImplInitFontList();
7332 :
7333 0 : if( !mpGraphics && !ImplGetGraphics() )
7334 0 : return sal_False;
7335 :
7336 0 : bool bRC = mpGraphics->AddTempDevFont( mpFontList, rFileURL, rFontName );
7337 0 : if( !bRC )
7338 0 : return sal_False;
7339 :
7340 0 : if( mpAlphaVDev )
7341 0 : mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
7342 :
7343 0 : mpFontCache->Invalidate();
7344 0 : return sal_True;
7345 : }
7346 :
7347 : // -----------------------------------------------------------------------
7348 :
7349 0 : int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
7350 : {
7351 : OSL_TRACE( "OutputDevice::GetDevFontSizeCount()" );
7352 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7353 :
7354 0 : delete mpGetDevSizeList;
7355 :
7356 0 : ImplInitFontList();
7357 0 : mpGetDevSizeList = mpFontList->GetDevSizeList( rFont.GetName() );
7358 0 : return mpGetDevSizeList->Count();
7359 : }
7360 :
7361 : // -----------------------------------------------------------------------
7362 :
7363 0 : Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
7364 : {
7365 : OSL_TRACE( "OutputDevice::GetDevFontSize()" );
7366 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7367 :
7368 : // check range
7369 0 : int nCount = GetDevFontSizeCount( rFont );
7370 0 : if ( nSizeIndex >= nCount )
7371 0 : return Size();
7372 :
7373 : // when mapping is enabled round to .5 points
7374 0 : Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
7375 0 : if ( mbMap )
7376 : {
7377 0 : aSize.Height() *= 10;
7378 0 : MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
7379 0 : aSize = PixelToLogic( aSize, aMap );
7380 0 : aSize.Height() += 5;
7381 0 : aSize.Height() /= 10;
7382 0 : long nRound = aSize.Height() % 5;
7383 0 : if ( nRound >= 3 )
7384 0 : aSize.Height() += (5-nRound);
7385 : else
7386 0 : aSize.Height() -= nRound;
7387 0 : aSize.Height() *= 10;
7388 0 : aSize = LogicToPixel( aSize, aMap );
7389 0 : aSize = PixelToLogic( aSize );
7390 0 : aSize.Height() += 5;
7391 0 : aSize.Height() /= 10;
7392 : }
7393 0 : return aSize;
7394 : }
7395 :
7396 : // -----------------------------------------------------------------------
7397 :
7398 22 : sal_Bool OutputDevice::IsFontAvailable( const String& rFontName ) const
7399 : {
7400 : OSL_TRACE( "OutputDevice::IsFontAvailable()" );
7401 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7402 :
7403 22 : ImplDevFontListData* pFound = mpFontList->FindFontFamily( rFontName );
7404 22 : return (pFound != NULL);
7405 : }
7406 :
7407 : // -----------------------------------------------------------------------
7408 :
7409 44756 : FontMetric OutputDevice::GetFontMetric() const
7410 : {
7411 : OSL_TRACE( "OutputDevice::GetFontMetric()" );
7412 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7413 :
7414 44756 : FontMetric aMetric;
7415 44756 : if( mbNewFont && !ImplNewFont() )
7416 0 : return aMetric;
7417 :
7418 44756 : ImplFontEntry* pEntry = mpFontEntry;
7419 44756 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
7420 :
7421 : // prepare metric
7422 44756 : aMetric.Font::operator=( maFont );
7423 :
7424 : // set aMetric with info from font
7425 44756 : aMetric.SetName( maFont.GetName() );
7426 44756 : aMetric.SetStyleName( pMetric->maStyleName );
7427 44756 : aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
7428 44756 : aMetric.SetCharSet( pMetric->mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
7429 44756 : aMetric.SetFamily( pMetric->meFamily );
7430 44756 : aMetric.SetPitch( pMetric->mePitch );
7431 44756 : aMetric.SetWeight( pMetric->meWeight );
7432 44756 : aMetric.SetItalic( pMetric->meItalic );
7433 44756 : aMetric.SetWidthType( pMetric->meWidthType );
7434 44756 : if ( pEntry->mnOwnOrientation )
7435 0 : aMetric.SetOrientation( pEntry->mnOwnOrientation );
7436 : else
7437 44756 : aMetric.SetOrientation( pMetric->mnOrientation );
7438 44756 : if( !pEntry->maMetric.mbKernableFont )
7439 37651 : aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
7440 :
7441 : // set remaining metric fields
7442 44756 : aMetric.mpImplMetric->mnMiscFlags = 0;
7443 44756 : if( pMetric->mbDevice )
7444 44756 : aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
7445 44756 : if( pMetric->mbScalableFont )
7446 44756 : aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
7447 44756 : aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
7448 44756 : aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
7449 44756 : aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
7450 44756 : aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
7451 44756 : aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
7452 44756 : aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
7453 :
7454 : #ifdef UNX
7455 : // backwards compatible line metrics after fixing #i60945#
7456 88624 : if( (meOutDevType == OUTDEV_VIRDEV)
7457 43868 : && static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
7458 0 : aMetric.mpImplMetric->mnExtLeading = 0;
7459 : #endif
7460 :
7461 44756 : return aMetric;
7462 : }
7463 :
7464 : // -----------------------------------------------------------------------
7465 :
7466 0 : FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
7467 : {
7468 : // select font, query metrics, select original font again
7469 0 : Font aOldFont = GetFont();
7470 0 : const_cast<OutputDevice*>(this)->SetFont( rFont );
7471 0 : FontMetric aMetric( GetFontMetric() );
7472 0 : const_cast<OutputDevice*>(this)->SetFont( aOldFont );
7473 0 : return aMetric;
7474 : }
7475 :
7476 : // -----------------------------------------------------------------------
7477 :
7478 : /** OutputDevice::GetSysFontData
7479 : *
7480 : * @param nFallbacklevel Fallback font level (0 = best matching font)
7481 : *
7482 : * Retrieve detailed font information in platform independent structure
7483 : *
7484 : * @return SystemFontData
7485 : **/
7486 0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
7487 : {
7488 0 : SystemFontData aSysFontData;
7489 0 : aSysFontData.nSize = sizeof(aSysFontData);
7490 :
7491 0 : if (!mpGraphics) ImplGetGraphics();
7492 0 : if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
7493 :
7494 0 : return aSysFontData;
7495 : }
7496 :
7497 :
7498 : // -----------------------------------------------------------------------
7499 :
7500 : /** OutputDevice::GetSysTextLayoutData
7501 : *
7502 : * @param rStartPt Start point of the text
7503 : * @param rStr Text string that will be transformed into layout of glyphs
7504 : * @param nIndex Position in the string from where layout will be done
7505 : * @param nLen Length of the string
7506 : * @param pDXAry Custom layout adjustment data
7507 : *
7508 : * Export finalized glyph layout data as platform independent SystemTextLayoutData
7509 : * (see vcl/inc/vcl/sysdata.hxx)
7510 : *
7511 : * Only parameters rStartPt and rStr are mandatory, the rest is optional
7512 : * (default values will be used)
7513 : *
7514 : * @return SystemTextLayoutData
7515 : **/
7516 0 : SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen,
7517 : const sal_Int32* pDXAry) const
7518 : {
7519 : OSL_TRACE( "OutputDevice::GetSysTextLayoutData()" );
7520 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7521 :
7522 0 : SystemTextLayoutData aSysLayoutData;
7523 0 : aSysLayoutData.nSize = sizeof(aSysLayoutData);
7524 0 : aSysLayoutData.rGlyphData.reserve( 256 );
7525 :
7526 0 : if ( mpMetaFile )
7527 : {
7528 0 : if (pDXAry)
7529 0 : mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
7530 : else
7531 0 : mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
7532 : }
7533 :
7534 0 : if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
7535 :
7536 0 : SalLayout* pLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
7537 :
7538 0 : if ( !pLayout ) return aSysLayoutData;
7539 :
7540 : // setup glyphs
7541 0 : Point aPos;
7542 : sal_GlyphId aGlyphId;
7543 0 : for( int nStart = 0; pLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
7544 : {
7545 : // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
7546 : // ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
7547 :
7548 : SystemGlyphData aGlyph;
7549 0 : aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
7550 0 : aGlyph.x = aPos.X();
7551 0 : aGlyph.y = aPos.Y();
7552 0 : int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
7553 0 : aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
7554 0 : aSysLayoutData.rGlyphData.push_back(aGlyph);
7555 : }
7556 :
7557 : // Get font data
7558 0 : aSysLayoutData.orientation = pLayout->GetOrientation();
7559 :
7560 0 : pLayout->Release();
7561 :
7562 0 : return aSysLayoutData;
7563 : }
7564 :
7565 : // -----------------------------------------------------------------------
7566 :
7567 :
7568 0 : long OutputDevice::GetMinKashida() const
7569 : {
7570 : OSL_TRACE( "OutputDevice::GetMinKashida()" );
7571 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7572 0 : if( mbNewFont && !ImplNewFont() )
7573 0 : return 0;
7574 :
7575 0 : ImplFontEntry* pEntry = mpFontEntry;
7576 0 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
7577 0 : return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
7578 : }
7579 :
7580 : // -----------------------------------------------------------------------
7581 0 : xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
7582 : xub_StrLen nIdx, xub_StrLen nLen,
7583 : xub_StrLen nKashCount,
7584 : const xub_StrLen* pKashidaPos,
7585 : xub_StrLen* pKashidaPosDropped ) const
7586 : {
7587 : // do layout
7588 0 : SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
7589 0 : if( !pSalLayout )
7590 0 : return 0;
7591 0 : xub_StrLen nDropped = 0;
7592 0 : for( int i = 0; i < nKashCount; ++i )
7593 : {
7594 0 : if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
7595 : {
7596 0 : pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
7597 0 : ++nDropped;
7598 : }
7599 : }
7600 0 : pSalLayout->Release();
7601 0 : return nDropped;
7602 : }
7603 :
7604 : // -----------------------------------------------------------------------
7605 :
7606 0 : sal_Bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const String& rStr,
7607 : int nIndex, int nLen, int nBase, MetricVector& rVector )
7608 : {
7609 : OSL_TRACE( "OutputDevice::GetGlyphBoundRect_CTL()" );
7610 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7611 :
7612 0 : rVector.clear();
7613 :
7614 0 : if( nLen == STRING_LEN )
7615 0 : nLen = rStr.Len() - nIndex;
7616 :
7617 0 : Rectangle aRect;
7618 0 : for( int i = 0; i < nLen; i++ )
7619 : {
7620 0 : if( !GetTextBoundRect( aRect, rStr, sal::static_int_cast<xub_StrLen>(nBase), sal::static_int_cast<xub_StrLen>(nIndex+i), 1 ) )
7621 0 : break;
7622 0 : aRect.Move( rOrigin.X(), rOrigin.Y() );
7623 0 : rVector.push_back( aRect );
7624 : }
7625 :
7626 0 : return (nLen == (int)rVector.size());
7627 : }
7628 :
7629 : // -----------------------------------------------------------------------
7630 :
7631 16968 : sal_Bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
7632 : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
7633 : sal_uLong nLayoutWidth, const sal_Int32* pDXAry ) const
7634 : {
7635 : OSL_TRACE( "OutputDevice::GetTextBoundRect()" );
7636 : DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7637 :
7638 16968 : sal_Bool bRet = sal_False;
7639 16968 : rRect.SetEmpty();
7640 :
7641 16968 : SalLayout* pSalLayout = NULL;
7642 16968 : const Point aPoint;
7643 : // calculate offset when nBase!=nIndex
7644 16968 : long nXOffset = 0;
7645 16968 : if( nBase != nIndex )
7646 : {
7647 0 : xub_StrLen nStart = Min( nBase, nIndex );
7648 0 : xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
7649 0 : pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
7650 0 : if( pSalLayout )
7651 : {
7652 0 : nXOffset = pSalLayout->GetTextWidth();
7653 0 : nXOffset /= pSalLayout->GetUnitsPerPixel();
7654 0 : pSalLayout->Release();
7655 : // TODO: fix offset calculation for Bidi case
7656 0 : if( nBase < nIndex)
7657 0 : nXOffset = -nXOffset;
7658 : }
7659 : }
7660 :
7661 16968 : pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
7662 16968 : Rectangle aPixelRect;
7663 16968 : if( pSalLayout )
7664 : {
7665 16968 : bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
7666 :
7667 16968 : if( bRet )
7668 : {
7669 16968 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
7670 :
7671 16968 : if( nWidthFactor > 1 )
7672 : {
7673 0 : double fFactor = 1.0 / nWidthFactor;
7674 0 : aPixelRect.Left()
7675 0 : = static_cast< long >(aPixelRect.Left() * fFactor);
7676 0 : aPixelRect.Right()
7677 0 : = static_cast< long >(aPixelRect.Right() * fFactor);
7678 0 : aPixelRect.Top()
7679 0 : = static_cast< long >(aPixelRect.Top() * fFactor);
7680 0 : aPixelRect.Bottom()
7681 0 : = static_cast< long >(aPixelRect.Bottom() * fFactor);
7682 : }
7683 :
7684 16968 : Point aRotatedOfs( mnTextOffX, mnTextOffY );
7685 16968 : aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
7686 16968 : aPixelRect += aRotatedOfs;
7687 16968 : rRect = PixelToLogic( aPixelRect );
7688 16968 : if( mbMap )
7689 4688 : rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
7690 : }
7691 :
7692 16968 : pSalLayout->Release();
7693 : }
7694 :
7695 16968 : if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
7696 16968 : return bRet;
7697 :
7698 : // fall back to bitmap method to get the bounding rectangle,
7699 : // so we need a monochrome virtual device with matching font
7700 0 : VirtualDevice aVDev( 1 );
7701 0 : Font aFont( GetFont() );
7702 0 : aFont.SetShadow( sal_False );
7703 0 : aFont.SetOutline( sal_False );
7704 0 : aFont.SetRelief( RELIEF_NONE );
7705 0 : aFont.SetOrientation( 0 );
7706 0 : aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
7707 0 : aVDev.SetFont( aFont );
7708 0 : aVDev.SetTextAlign( ALIGN_TOP );
7709 :
7710 : // layout the text on the virtual device
7711 0 : pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
7712 0 : if( !pSalLayout )
7713 0 : return false;
7714 :
7715 : // make the bitmap big enough
7716 : // TODO: use factors when it would get too big
7717 0 : long nWidth = pSalLayout->GetTextWidth();
7718 0 : long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
7719 0 : Point aOffset( nWidth/2, 8 );
7720 0 : Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
7721 0 : if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
7722 0 : return false;
7723 :
7724 : // draw text in black
7725 0 : pSalLayout->DrawBase() = aOffset;
7726 0 : aVDev.SetTextColor( Color( COL_BLACK ) );
7727 0 : aVDev.SetTextFillColor();
7728 0 : aVDev.ImplInitTextColor();
7729 0 : aVDev.ImplDrawText( *pSalLayout );
7730 0 : pSalLayout->Release();
7731 :
7732 : // find extents using the bitmap
7733 0 : Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
7734 0 : BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
7735 0 : if( !pAcc )
7736 0 : return sal_False;
7737 0 : const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
7738 0 : const long nW = pAcc->Width();
7739 0 : const long nH = pAcc->Height();
7740 0 : long nLeft = 0;
7741 0 : long nRight = 0;
7742 :
7743 : // find top left point
7744 0 : long nTop = 0;
7745 0 : for(; nTop < nH; ++nTop )
7746 : {
7747 0 : for( nLeft = 0; nLeft < nW; ++nLeft )
7748 0 : if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
7749 0 : break;
7750 0 : if( nLeft < nW )
7751 0 : break;
7752 : }
7753 :
7754 : // find bottom right point
7755 0 : long nBottom = nH;
7756 0 : while( --nBottom >= nTop )
7757 : {
7758 0 : for( nRight = nW; --nRight >= 0; )
7759 0 : if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
7760 0 : break;
7761 0 : if( nRight >= 0 )
7762 0 : break;
7763 : }
7764 0 : if( nRight < nLeft )
7765 : {
7766 0 : long nX = nRight;
7767 0 : nRight = nLeft;
7768 0 : nLeft = nX;
7769 : }
7770 :
7771 0 : for( long nY = nTop; nY <= nBottom; ++nY )
7772 : {
7773 : // find leftmost point
7774 : long nX;
7775 0 : for( nX = 0; nX < nLeft; ++nX )
7776 0 : if( pAcc->GetPixel( nY, nX ) == aBlack )
7777 0 : break;
7778 0 : nLeft = nX;
7779 :
7780 : // find rightmost point
7781 0 : for( nX = nW; --nX > nRight; )
7782 0 : if( pAcc->GetPixel( nY, nX ) == aBlack )
7783 0 : break;
7784 0 : nRight = nX;
7785 : }
7786 :
7787 0 : aBmp.ReleaseAccess( pAcc );
7788 :
7789 0 : if( nTop <= nBottom )
7790 : {
7791 0 : Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
7792 0 : Point aTopLeft( nLeft, nTop );
7793 0 : aTopLeft -= aOffset;
7794 : // adjust to text alignment
7795 0 : aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
7796 : // convert to logical coordinates
7797 0 : aSize = PixelToLogic( aSize );
7798 0 : aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
7799 0 : aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
7800 0 : rRect = Rectangle( aTopLeft, aSize );
7801 0 : return sal_True;
7802 : }
7803 :
7804 0 : return sal_False;
7805 : }
7806 :
7807 : // -----------------------------------------------------------------------
7808 :
7809 119 : sal_Bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
7810 : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
7811 : sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
7812 : {
7813 : // the fonts need to be initialized
7814 119 : if( mbNewFont )
7815 20 : ImplNewFont();
7816 119 : if( mbInitFont )
7817 0 : ImplInitFont();
7818 119 : if( !mpFontEntry )
7819 0 : return sal_False;
7820 :
7821 119 : sal_Bool bRet = sal_False;
7822 119 : rVector.clear();
7823 119 : if( nLen == STRING_LEN )
7824 119 : nLen = rStr.Len() - nIndex;
7825 119 : rVector.reserve( nLen );
7826 :
7827 : // we want to get the Rectangle in logical units, so to
7828 : // avoid rounding errors we just size the font in logical units
7829 119 : sal_Bool bOldMap = mbMap;
7830 119 : if( bOldMap )
7831 : {
7832 119 : const_cast<OutputDevice&>(*this).mbMap = sal_False;
7833 119 : const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
7834 : }
7835 :
7836 119 : SalLayout* pSalLayout = NULL;
7837 :
7838 : // calculate offset when nBase!=nIndex
7839 119 : long nXOffset = 0;
7840 119 : if( nBase != nIndex )
7841 : {
7842 0 : xub_StrLen nStart = Min( nBase, nIndex );
7843 0 : xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
7844 0 : pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nTWidth, pDXArray );
7845 0 : if( pSalLayout )
7846 : {
7847 0 : nXOffset = pSalLayout->GetTextWidth();
7848 0 : pSalLayout->Release();
7849 : // TODO: fix offset calculation for Bidi case
7850 0 : if( nBase > nIndex)
7851 0 : nXOffset = -nXOffset;
7852 : }
7853 : }
7854 :
7855 119 : pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7856 119 : if( pSalLayout )
7857 : {
7858 119 : bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
7859 119 : if( bRet )
7860 : {
7861 : // transform polygon to pixel units
7862 73 : ::basegfx::B2DHomMatrix aMatrix;
7863 :
7864 73 : int nWidthFactor = pSalLayout->GetUnitsPerPixel();
7865 73 : if( nXOffset | mnTextOffX | mnTextOffY )
7866 : {
7867 0 : Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
7868 0 : aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
7869 0 : aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
7870 : }
7871 :
7872 73 : if( nWidthFactor > 1 )
7873 : {
7874 0 : double fFactor = 1.0 / nWidthFactor;
7875 0 : aMatrix.scale( fFactor, fFactor );
7876 : }
7877 :
7878 73 : if( !aMatrix.isIdentity() )
7879 : {
7880 0 : ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
7881 0 : for(; aIt != rVector.end(); ++aIt )
7882 0 : (*aIt).transform( aMatrix );
7883 73 : }
7884 : }
7885 :
7886 119 : pSalLayout->Release();
7887 : }
7888 :
7889 119 : if( bOldMap )
7890 : {
7891 : // restore original font size and map mode
7892 119 : const_cast<OutputDevice&>(*this).mbMap = bOldMap;
7893 119 : const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
7894 : }
7895 :
7896 119 : if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
7897 73 : return bRet;
7898 :
7899 : // fall back to bitmap conversion ------------------------------------------
7900 :
7901 : // Here, we can savely assume that the mapping between characters and glyphs
7902 : // is one-to-one. This is most probably valid for the old bitmap fonts.
7903 :
7904 : // fall back to bitmap method to get the bounding rectangle,
7905 : // so we need a monochrome virtual device with matching font
7906 46 : pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7907 46 : if (pSalLayout == 0)
7908 0 : return false;
7909 46 : long nOrgWidth = pSalLayout->GetTextWidth();
7910 : long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
7911 46 : + mnEmphasisDescent;
7912 46 : pSalLayout->Release();
7913 :
7914 46 : VirtualDevice aVDev(1);
7915 :
7916 46 : Font aFont(GetFont());
7917 46 : aFont.SetShadow(false);
7918 46 : aFont.SetOutline(false);
7919 46 : aFont.SetRelief(RELIEF_NONE);
7920 46 : aFont.SetOrientation(0);
7921 46 : if( bOptimize )
7922 : {
7923 46 : aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
7924 46 : aVDev.SetMapMode( MAP_PIXEL );
7925 : }
7926 46 : aVDev.SetFont( aFont );
7927 46 : aVDev.SetTextAlign( ALIGN_TOP );
7928 46 : aVDev.SetTextColor( Color(COL_BLACK) );
7929 46 : aVDev.SetTextFillColor();
7930 :
7931 46 : pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7932 46 : if (pSalLayout == 0)
7933 0 : return false;
7934 46 : long nWidth = pSalLayout->GetTextWidth();
7935 : long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
7936 46 : + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
7937 46 : pSalLayout->Release();
7938 :
7939 46 : if( !nWidth || !nHeight )
7940 11 : return sal_True;
7941 35 : double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
7942 35 : double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
7943 :
7944 : // calculate offset when nBase!=nIndex
7945 : // TODO: fix offset calculation for Bidi case
7946 35 : nXOffset = 0;
7947 35 : if( nBase != nIndex )
7948 : {
7949 0 : xub_StrLen nStart = ((nBase < nIndex) ? nBase : nIndex);
7950 0 : xub_StrLen nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
7951 0 : pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nTWidth, pDXArray );
7952 0 : if( pSalLayout )
7953 : {
7954 0 : nXOffset = pSalLayout->GetTextWidth();
7955 0 : pSalLayout->Release();
7956 0 : if( nBase > nIndex)
7957 0 : nXOffset = -nXOffset;
7958 : }
7959 : }
7960 :
7961 35 : bRet = true;
7962 35 : bool bRTL = false;
7963 35 : String aStr( rStr ); // prepare for e.g. localized digits
7964 35 : ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
7965 105 : for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
7966 : {
7967 35 : bool bSuccess = false;
7968 :
7969 : // draw character into virtual device
7970 35 : pSalLayout = aVDev.ImplLayout( rStr, static_cast< xub_StrLen >(nCharPos), 1, Point(0,0), nTWidth, pDXArray );
7971 35 : if (pSalLayout == 0)
7972 0 : return false;
7973 35 : long nCharWidth = pSalLayout->GetTextWidth();
7974 :
7975 35 : Point aOffset(nCharWidth / 2, 8);
7976 35 : Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
7977 35 : bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
7978 35 : if( bSuccess )
7979 : {
7980 : // draw glyph into virtual device
7981 35 : aVDev.Erase();
7982 35 : pSalLayout->DrawBase() += aOffset;
7983 35 : pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
7984 35 : pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
7985 35 : pSalLayout->Release();
7986 :
7987 : // convert character image into outline
7988 35 : Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
7989 :
7990 35 : PolyPolygon aPolyPoly;
7991 35 : bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
7992 35 : if( !bVectorized )
7993 0 : bSuccess = false;
7994 : else
7995 : {
7996 : // convert units to logical width
7997 35 : for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
7998 : {
7999 0 : Polygon& rPoly = aPolyPoly[j];
8000 0 : for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
8001 : {
8002 0 : Point& rPt = rPoly[k];
8003 0 : rPt -= aOffset;
8004 0 : int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
8005 0 : int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
8006 0 : rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
8007 0 : rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
8008 : }
8009 : }
8010 :
8011 :
8012 : // ignore "empty" glyphs:
8013 35 : if( aPolyPoly.Count() > 0 )
8014 : {
8015 : // convert to B2DPolyPolygon
8016 : // TODO: get rid of intermediate tool's PolyPolygon
8017 0 : ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
8018 0 : ::basegfx::B2DHomMatrix aMatrix;
8019 0 : aMatrix.scale( fScaleX, fScaleY );
8020 0 : int nAngle = GetFont().GetOrientation();
8021 0 : if( nAngle )
8022 0 : aMatrix.rotate( nAngle * F_PI1800 );
8023 0 : aB2DPolyPoly.transform( aMatrix );
8024 0 : rVector.push_back( aB2DPolyPoly );
8025 : }
8026 35 : }
8027 : }
8028 :
8029 35 : nXOffset += nCharWidth;
8030 35 : bRet = bRet && bSuccess;
8031 : }
8032 :
8033 35 : return bRet;
8034 : }
8035 :
8036 : // -----------------------------------------------------------------------
8037 :
8038 119 : sal_Bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
8039 : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex,
8040 : xub_StrLen nLen, sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
8041 : {
8042 119 : rResultVector.clear();
8043 :
8044 : // get the basegfx polypolygon vector
8045 119 : ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
8046 119 : if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
8047 119 : bOptimize, nTWidth, pDXArray ) )
8048 0 : return sal_False;
8049 :
8050 : // convert to a tool polypolygon vector
8051 119 : rResultVector.reserve( aB2DPolyPolyVector.size() );
8052 119 : ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
8053 192 : for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
8054 73 : rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
8055 :
8056 119 : return sal_True;
8057 : }
8058 :
8059 : // -----------------------------------------------------------------------
8060 :
8061 0 : sal_Bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly,
8062 : const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
8063 : sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
8064 : {
8065 0 : rPolyPoly.Clear();
8066 :
8067 : // get the basegfx polypolygon vector
8068 0 : ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
8069 0 : if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
8070 0 : bOptimize, nTWidth, pDXArray ) )
8071 0 : return sal_False;
8072 :
8073 : // convert and merge into a tool polypolygon
8074 0 : ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
8075 0 : for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
8076 0 : for( unsigned int i = 0; i < aIt->count(); ++i )
8077 0 : rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
8078 :
8079 0 : return sal_True;
8080 : }
8081 :
8082 0 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
8083 : {
8084 : // we need a graphics
8085 0 : if( !mpGraphics && !ImplGetGraphics() )
8086 0 : return false;
8087 :
8088 0 : if( mbNewFont )
8089 0 : ImplNewFont();
8090 0 : if( mbInitFont )
8091 0 : ImplInitFont();
8092 0 : if( !mpFontEntry )
8093 0 : return false;
8094 :
8095 0 : return mpGraphics->GetImplFontCapabilities(rFontCapabilities);
8096 : }
8097 :
8098 : // -----------------------------------------------------------------------
8099 :
8100 2841 : sal_Bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
8101 : {
8102 2841 : rFontCharMap.Reset();
8103 :
8104 : // we need a graphics
8105 2841 : if( !mpGraphics && !ImplGetGraphics() )
8106 0 : return sal_False;
8107 :
8108 2841 : if( mbNewFont )
8109 2510 : ImplNewFont();
8110 2841 : if( mbInitFont )
8111 68 : ImplInitFont();
8112 2841 : if( !mpFontEntry )
8113 0 : return sal_False;
8114 :
8115 : #ifdef ENABLE_IFC_CACHE // a little font charmap cache helps considerably
8116 : static const int NMAXITEMS = 16;
8117 : static int nUsedItems = 0, nCurItem = 0;
8118 :
8119 : struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; };
8120 : static CharMapCacheItem aCache[ NMAXITEMS ];
8121 :
8122 : const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData;
8123 :
8124 : int i;
8125 : for( i = nUsedItems; --i >= 0; )
8126 : if( pFontData == aCache[i].mpFontData )
8127 : break;
8128 : if( i >= 0 ) // found in cache
8129 : {
8130 : rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
8131 : }
8132 : else // need to cache
8133 : #endif // ENABLE_IFC_CACHE
8134 : {
8135 2841 : const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
8136 2841 : rFontCharMap.Reset( pNewMap );
8137 :
8138 : #ifdef ENABLE_IFC_CACHE
8139 : // manage cache round-robin and insert data
8140 : CharMapCacheItem& rItem = aCache[ nCurItem ];
8141 : rItem.mpFontData = pFontData;
8142 : rItem.maCharMap.Reset( pNewMap );
8143 :
8144 : if( ++nCurItem >= NMAXITEMS )
8145 : nCurItem = 0;
8146 :
8147 : if( ++nUsedItems >= NMAXITEMS )
8148 : nUsedItems = NMAXITEMS;
8149 : #endif // ENABLE_IFC_CACHE
8150 : }
8151 :
8152 2841 : if( rFontCharMap.IsDefaultMap() )
8153 0 : return sal_False;
8154 2841 : return sal_True;
8155 : }
8156 :
8157 : // -----------------------------------------------------------------------
8158 :
8159 2114 : xub_StrLen OutputDevice::HasGlyphs( const Font& rTempFont, const String& rStr,
8160 : xub_StrLen nIndex, xub_StrLen nLen ) const
8161 : {
8162 2114 : if( nIndex >= rStr.Len() )
8163 0 : return nIndex;
8164 2114 : xub_StrLen nEnd = nIndex + nLen;
8165 2114 : if( (sal_uLong)nIndex+nLen > rStr.Len() )
8166 8 : nEnd = rStr.Len();
8167 :
8168 : DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
8169 : DBG_ASSERT( nEnd <= rStr.Len(), "String too short" );
8170 :
8171 : // to get the map temporarily set font
8172 2114 : const Font aOrigFont = GetFont();
8173 2114 : const_cast<OutputDevice&>(*this).SetFont( rTempFont );
8174 2114 : FontCharMap aFontCharMap;
8175 2114 : sal_Bool bRet = GetFontCharMap( aFontCharMap );
8176 2114 : const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
8177 :
8178 : // if fontmap is unknown assume it doesn't have the glyphs
8179 2114 : if( bRet == sal_False )
8180 0 : return nIndex;
8181 :
8182 2114 : const sal_Unicode* pStr = rStr.GetBuffer();
8183 2548 : for( pStr += nIndex; nIndex < nEnd; ++pStr, ++nIndex )
8184 2514 : if( ! aFontCharMap.HasChar( *pStr ) )
8185 2080 : return nIndex;
8186 :
8187 34 : return STRING_LEN;
8188 : }
8189 :
8190 : // -----------------------------------------------------------------------
8191 :
8192 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|