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