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 "i18nlangtag/mslangid.hxx"
21 :
22 : #include <vcl/virdev.hxx>
23 : #include <vcl/print.hxx>
24 : #include <vcl/outdev.hxx>
25 : #include <vcl/edit.hxx>
26 : #include <vcl/settings.hxx>
27 : #include <vcl/sysdata.hxx>
28 :
29 : #include "sallayout.hxx"
30 : #include "svdata.hxx"
31 :
32 : #include "impfont.hxx"
33 : #include "outdata.hxx"
34 : #include "outfont.hxx"
35 :
36 : #include "outdev.h"
37 : #include "window.h"
38 :
39 : #include "PhysicalFontCollection.hxx"
40 : #include "PhysicalFontFace.hxx"
41 : #include "PhysicalFontFamily.hxx"
42 :
43 : #include "svids.hrc"
44 :
45 : #include <config_graphite.h>
46 : #if ENABLE_GRAPHITE
47 : #include "graphite_features.hxx"
48 : #endif
49 :
50 : #include "../gdi/pdfwriter_impl.hxx"
51 :
52 : #include <cmath>
53 : #include <cstring>
54 :
55 : #include <memory>
56 : #include <algorithm>
57 :
58 : using namespace ::com::sun::star;
59 : using namespace ::com::sun::star::uno;
60 : using namespace ::rtl;
61 : using namespace ::utl;
62 : using namespace ::vcl;
63 :
64 1674144 : vcl::FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
65 : {
66 1674144 : vcl::FontInfo aFontInfo;
67 :
68 1674144 : ImplInitFontList();
69 :
70 1674144 : int nCount = GetDevFontCount();
71 1674144 : if( nDevFontIndex < nCount )
72 : {
73 1674144 : const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
74 1674144 : aFontInfo.SetName( rData.GetFamilyName() );
75 1674144 : aFontInfo.SetStyleName( rData.GetStyleName() );
76 1674144 : aFontInfo.SetCharSet( rData.IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
77 1674144 : aFontInfo.SetFamily( rData.GetFamilyType() );
78 1674144 : aFontInfo.SetPitch( rData.GetPitch() );
79 1674144 : aFontInfo.SetWeight( rData.GetWeight() );
80 1674144 : aFontInfo.SetItalic( rData.GetSlant() );
81 1674144 : aFontInfo.SetWidthType( rData.GetWidthType() );
82 1674144 : if( rData.IsScalable() )
83 1674144 : aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
84 1674144 : if( rData.mbDevice )
85 0 : aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
86 : }
87 :
88 1674144 : return aFontInfo;
89 : }
90 :
91 1686012 : int OutputDevice::GetDevFontCount() const
92 : {
93 1686012 : if( !mpGetDevFontList )
94 8012 : mpGetDevFontList = mpFontCollection->GetDevFontList();
95 1686012 : return mpGetDevFontList->Count();
96 : }
97 :
98 70 : bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const
99 : {
100 70 : PhysicalFontFamily* pFound = mpFontCollection->FindFontFamily( rFontName );
101 70 : return (pFound != NULL);
102 : }
103 :
104 2058 : int OutputDevice::GetDevFontSizeCount( const vcl::Font& rFont ) const
105 : {
106 2058 : delete mpGetDevSizeList;
107 :
108 2058 : ImplInitFontList();
109 2058 : mpGetDevSizeList = mpFontCollection->GetDevSizeList( rFont.GetName() );
110 2058 : return mpGetDevSizeList->Count();
111 : }
112 :
113 0 : Size OutputDevice::GetDevFontSize( const vcl::Font& rFont, int nSizeIndex ) const
114 : {
115 : // check range
116 0 : int nCount = GetDevFontSizeCount( rFont );
117 0 : if ( nSizeIndex >= nCount )
118 0 : return Size();
119 :
120 : // when mapping is enabled round to .5 points
121 0 : Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
122 0 : if ( mbMap )
123 : {
124 0 : aSize.Height() *= 10;
125 0 : MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
126 0 : aSize = PixelToLogic( aSize, aMap );
127 0 : aSize.Height() += 5;
128 0 : aSize.Height() /= 10;
129 0 : long nRound = aSize.Height() % 5;
130 0 : if ( nRound >= 3 )
131 0 : aSize.Height() += (5-nRound);
132 : else
133 0 : aSize.Height() -= nRound;
134 0 : aSize.Height() *= 10;
135 0 : aSize = LogicToPixel( aSize, aMap );
136 0 : aSize = PixelToLogic( aSize );
137 0 : aSize.Height() += 5;
138 0 : aSize.Height() /= 10;
139 : }
140 0 : return aSize;
141 : }
142 :
143 0 : bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName )
144 : {
145 0 : ImplInitFontList();
146 :
147 0 : if( !mpGraphics && !AcquireGraphics() )
148 0 : return false;
149 :
150 0 : bool bRC = mpGraphics->AddTempDevFont( mpFontCollection, rFileURL, rFontName );
151 0 : if( !bRC )
152 0 : return false;
153 :
154 0 : if( mpAlphaVDev )
155 0 : mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
156 :
157 0 : mpFontCache->Invalidate();
158 0 : return true;
159 : }
160 :
161 563210 : FontMetric OutputDevice::GetFontMetric() const
162 : {
163 563210 : FontMetric aMetric;
164 563210 : if( mbNewFont && !ImplNewFont() )
165 0 : return aMetric;
166 :
167 563210 : ImplFontEntry* pEntry = mpFontEntry;
168 563210 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
169 :
170 : // prepare metric
171 563210 : aMetric.Font::operator=( maFont );
172 :
173 : // set aMetric with info from font
174 563210 : aMetric.SetName( maFont.GetName() );
175 563210 : aMetric.SetStyleName( pMetric->GetStyleName() );
176 563210 : aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
177 563210 : aMetric.SetCharSet( pMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
178 563210 : aMetric.SetFamily( pMetric->GetFamilyType() );
179 563210 : aMetric.SetPitch( pMetric->GetPitch() );
180 563210 : aMetric.SetWeight( pMetric->GetWeight() );
181 563210 : aMetric.SetItalic( pMetric->GetSlant() );
182 563210 : aMetric.SetWidthType( pMetric->GetWidthType() );
183 563210 : if ( pEntry->mnOwnOrientation )
184 0 : aMetric.SetOrientation( pEntry->mnOwnOrientation );
185 : else
186 563210 : aMetric.SetOrientation( pMetric->mnOrientation );
187 563210 : if( !pEntry->maMetric.mbKernableFont )
188 88849 : aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
189 :
190 : // set remaining metric fields
191 563210 : aMetric.mpImplMetric->mnMiscFlags = 0;
192 563210 : if( pMetric->mbDevice )
193 554826 : aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
194 563210 : if( pMetric->mbScalableFont )
195 563210 : aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
196 563210 : aMetric.mpImplMetric->mnAscent = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
197 563210 : aMetric.mpImplMetric->mnDescent = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
198 563210 : aMetric.mpImplMetric->mnIntLeading = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
199 563210 : aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( GetFontExtLeading() );
200 563210 : aMetric.mpImplMetric->mnExtLeading = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
201 563210 : aMetric.mpImplMetric->mnLineHeight = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
202 563210 : aMetric.mpImplMetric->mnSlant = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
203 :
204 : SAL_INFO("vcl.gdi.fontmetric", "OutputDevice::GetFontMetric:" << aMetric);
205 :
206 563210 : return aMetric;
207 : }
208 :
209 0 : FontMetric OutputDevice::GetFontMetric( const vcl::Font& rFont ) const
210 : {
211 : // select font, query metrics, select original font again
212 0 : Font aOldFont = GetFont();
213 0 : const_cast<OutputDevice*>(this)->SetFont( rFont );
214 0 : FontMetric aMetric( GetFontMetric() );
215 0 : const_cast<OutputDevice*>(this)->SetFont( aOldFont );
216 0 : return aMetric;
217 : }
218 :
219 13910 : bool OutputDevice::GetFontCharMap( FontCharMapPtr& rFontCharMap ) const
220 : {
221 : // we need a graphics
222 13910 : if( !mpGraphics && !AcquireGraphics() )
223 0 : return false;
224 :
225 13910 : if( mbNewFont )
226 12878 : ImplNewFont();
227 13910 : if( mbInitFont )
228 2038 : InitFont();
229 13910 : if( !mpFontEntry )
230 0 : return false;
231 :
232 13910 : FontCharMapPtr pFontCharMap ( mpGraphics->GetFontCharMap() );
233 13910 : if (!pFontCharMap)
234 : {
235 0 : FontCharMapPtr pDefaultMap( new FontCharMap() );
236 0 : rFontCharMap = pDefaultMap;
237 : }
238 : else
239 13910 : rFontCharMap = pFontCharMap;
240 :
241 13910 : if( rFontCharMap->IsDefaultMap() )
242 0 : return false;
243 13910 : return true;
244 : }
245 :
246 1712 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
247 : {
248 : // we need a graphics
249 1712 : if( !mpGraphics && !AcquireGraphics() )
250 0 : return false;
251 :
252 1712 : if( mbNewFont )
253 0 : ImplNewFont();
254 1712 : if( mbInitFont )
255 0 : InitFont();
256 1712 : if( !mpFontEntry )
257 0 : return false;
258 :
259 1712 : return mpGraphics->GetFontCapabilities(rFontCapabilities);
260 : }
261 :
262 0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
263 : {
264 0 : SystemFontData aSysFontData;
265 0 : aSysFontData.nSize = sizeof(aSysFontData);
266 :
267 0 : if (!mpGraphics)
268 0 : (void) AcquireGraphics();
269 :
270 0 : if (mpGraphics)
271 0 : aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
272 :
273 0 : return aSysFontData;
274 : }
275 :
276 10674 : void OutputDevice::ImplGetEmphasisMark( tools::PolyPolygon& rPolyPoly, bool& rPolyLine,
277 : Rectangle& rRect1, Rectangle& rRect2,
278 : long& rYOff, long& rWidth,
279 : FontEmphasisMark eEmphasis,
280 : long nHeight, short /*nOrient*/ )
281 : {
282 : static const sal_uInt8 aAccentPolyFlags[24] =
283 : {
284 : 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
285 : };
286 :
287 : static const long aAccentPos[48] =
288 : {
289 : 78, 0,
290 : 348, 79,
291 : 599, 235,
292 : 843, 469,
293 : 938, 574,
294 : 990, 669,
295 : 990, 773,
296 : 990, 843,
297 : 964, 895,
298 : 921, 947,
299 : 886, 982,
300 : 860, 999,
301 : 825, 999,
302 : 764, 999,
303 : 721, 964,
304 : 686, 895,
305 : 625, 791,
306 : 556, 660,
307 : 469, 504,
308 : 400, 400,
309 : 261, 252,
310 : 61, 61,
311 : 0, 27,
312 : 9, 0
313 : };
314 :
315 10674 : rWidth = 0;
316 10674 : rYOff = 0;
317 10674 : rPolyLine = false;
318 :
319 10674 : if ( !nHeight )
320 10674 : return;
321 :
322 10674 : FontEmphasisMark nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
323 10674 : long nDotSize = 0;
324 10674 : switch ( nEmphasisStyle )
325 : {
326 : case EMPHASISMARK_DOT:
327 : // Dot has 55% of the height
328 2370 : nDotSize = (nHeight*550)/1000;
329 2370 : if ( !nDotSize )
330 268 : nDotSize = 1;
331 2370 : if ( nDotSize <= 2 )
332 1274 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
333 : else
334 : {
335 1096 : long nRad = nDotSize/2;
336 1096 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
337 1096 : rPolyPoly.Insert( aPoly );
338 : }
339 2370 : rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks
340 2370 : rWidth = nDotSize;
341 2370 : break;
342 :
343 : case EMPHASISMARK_CIRCLE:
344 : // Dot has 80% of the height
345 3822 : nDotSize = (nHeight*800)/1000;
346 3822 : if ( !nDotSize )
347 224 : nDotSize = 1;
348 3822 : if ( nDotSize <= 2 )
349 542 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
350 : else
351 : {
352 3280 : long nRad = nDotSize/2;
353 3280 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
354 3280 : rPolyPoly.Insert( aPoly );
355 : // BorderWidth is 15%
356 3280 : long nBorder = (nDotSize*150)/1000;
357 3280 : if ( nBorder <= 1 )
358 2816 : rPolyLine = true;
359 : else
360 : {
361 : Polygon aPoly2( Point( nRad, nRad ),
362 464 : nRad-nBorder, nRad-nBorder );
363 464 : rPolyPoly.Insert( aPoly2 );
364 3280 : }
365 : }
366 3822 : rWidth = nDotSize;
367 3822 : break;
368 :
369 : case EMPHASISMARK_DISC:
370 : // Dot has 80% of the height
371 3834 : nDotSize = (nHeight*800)/1000;
372 3834 : if ( !nDotSize )
373 0 : nDotSize = 1;
374 3834 : if ( nDotSize <= 2 )
375 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
376 : else
377 : {
378 3834 : long nRad = nDotSize/2;
379 3834 : Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
380 3834 : rPolyPoly.Insert( aPoly );
381 : }
382 3834 : rWidth = nDotSize;
383 3834 : break;
384 :
385 : case EMPHASISMARK_ACCENT:
386 : // Dot has 80% of the height
387 648 : nDotSize = (nHeight*800)/1000;
388 648 : if ( !nDotSize )
389 0 : nDotSize = 1;
390 648 : if ( nDotSize <= 2 )
391 : {
392 0 : if ( nDotSize == 1 )
393 : {
394 0 : rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
395 0 : rWidth = nDotSize;
396 : }
397 : else
398 : {
399 0 : rRect1 = Rectangle( Point(), Size( 1, 1 ) );
400 0 : rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
401 : }
402 : }
403 : else
404 : {
405 648 : Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
406 : (const Point*)aAccentPos,
407 648 : aAccentPolyFlags );
408 648 : double dScale = ((double)nDotSize)/1000.0;
409 648 : aPoly.Scale( dScale, dScale );
410 1296 : Polygon aTemp;
411 648 : aPoly.AdaptiveSubdivide( aTemp );
412 648 : Rectangle aBoundRect = aTemp.GetBoundRect();
413 648 : rWidth = aBoundRect.GetWidth();
414 648 : nDotSize = aBoundRect.GetHeight();
415 1296 : rPolyPoly.Insert( aTemp );
416 : }
417 648 : break;
418 : }
419 :
420 : // calculate position
421 10674 : long nOffY = 1+(mnDPIY/300); // one visible pixel space
422 10674 : long nSpaceY = nHeight-nDotSize;
423 10674 : if ( nSpaceY >= nOffY*2 )
424 8672 : rYOff += nOffY;
425 10674 : if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
426 10674 : rYOff += nDotSize;
427 : }
428 :
429 66327 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const vcl::Font& rFont )
430 : {
431 66327 : FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
432 :
433 : // If no Position is set, then calculate the default position, which
434 : // depends on the language
435 66327 : if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
436 : {
437 10252 : LanguageType eLang = rFont.GetLanguage();
438 : // In Chinese Simplified the EmphasisMarks are below/left
439 10252 : if (MsLangId::isSimplifiedChinese(eLang))
440 0 : nEmphasisMark |= EMPHASISMARK_POS_BELOW;
441 : else
442 : {
443 10252 : eLang = rFont.GetCJKContextLanguage();
444 : // In Chinese Simplified the EmphasisMarks are below/left
445 10252 : if (MsLangId::isSimplifiedChinese(eLang))
446 0 : nEmphasisMark |= EMPHASISMARK_POS_BELOW;
447 : else
448 10252 : nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
449 : }
450 : }
451 :
452 66327 : return nEmphasisMark;
453 : }
454 :
455 31504 : long OutputDevice::GetFontExtLeading() const
456 : {
457 31504 : ImplFontEntry* pEntry = mpFontEntry;
458 31504 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
459 :
460 31504 : return pMetric->mnExtLeading;
461 : }
462 :
463 100 : void OutputDevice::ImplClearFontData( const bool bNewFontLists )
464 : {
465 : // the currently selected logical font is no longer needed
466 100 : if ( mpFontEntry )
467 : {
468 0 : mpFontCache->Release( mpFontEntry );
469 0 : mpFontEntry = NULL;
470 : }
471 :
472 100 : mbInitFont = true;
473 100 : mbNewFont = true;
474 :
475 100 : if ( bNewFontLists )
476 : {
477 100 : if ( mpGetDevFontList )
478 : {
479 0 : delete mpGetDevFontList;
480 0 : mpGetDevFontList = NULL;
481 : }
482 100 : if ( mpGetDevSizeList )
483 : {
484 0 : delete mpGetDevSizeList;
485 0 : mpGetDevSizeList = NULL;
486 : }
487 :
488 : // release all physically selected fonts on this device
489 100 : if( AcquireGraphics() )
490 100 : mpGraphics->ReleaseFonts();
491 : }
492 :
493 : // if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
494 : {
495 100 : ImplSVData* pSVData = ImplGetSVData();
496 :
497 100 : if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
498 100 : mpFontCache->Invalidate();
499 :
500 100 : if ( bNewFontLists )
501 : {
502 : // we need a graphics
503 100 : if ( AcquireGraphics() )
504 : {
505 100 : if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList )
506 100 : mpFontCollection->Clear();
507 :
508 100 : if( mpPDFWriter )
509 : {
510 0 : if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList )
511 0 : delete mpFontCollection;
512 0 : if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
513 0 : delete mpFontCache;
514 0 : mpFontCollection = 0;
515 0 : mpFontCache = 0;
516 : }
517 : }
518 : }
519 : }
520 :
521 : // also update child windows if needed
522 100 : if ( GetOutDevType() == OUTDEV_WINDOW )
523 : {
524 0 : vcl::Window* pChild = static_cast<vcl::Window*>(this)->mpWindowImpl->mpFirstChild;
525 0 : while ( pChild )
526 : {
527 0 : pChild->ImplClearFontData( true );
528 0 : pChild = pChild->mpWindowImpl->mpNext;
529 : }
530 : }
531 100 : }
532 :
533 100 : void OutputDevice::ImplRefreshFontData( const bool bNewFontLists )
534 : {
535 : // if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
536 : {
537 100 : ImplSVData* pSVData = ImplGetSVData();
538 :
539 100 : if ( bNewFontLists )
540 : {
541 : // we need a graphics
542 100 : if ( AcquireGraphics() )
543 : {
544 100 : if( mpPDFWriter )
545 : {
546 0 : mpFontCollection = pSVData->maGDIData.mpScreenFontList->Clone( true, true );
547 0 : mpFontCache = new ImplFontCache();
548 : }
549 : else
550 : {
551 100 : mpGraphics->GetDevFontList( mpFontCollection );
552 : }
553 : }
554 : }
555 : }
556 :
557 : // also update child windows if needed
558 100 : if ( GetOutDevType() == OUTDEV_WINDOW )
559 : {
560 0 : vcl::Window* pChild = static_cast<vcl::Window*>(this)->mpWindowImpl->mpFirstChild;
561 0 : while ( pChild )
562 : {
563 0 : pChild->ImplRefreshFontData( true );
564 0 : pChild = pChild->mpWindowImpl->mpNext;
565 : }
566 : }
567 100 : }
568 :
569 100 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
570 : {
571 100 : ImplClearFontData( bNewFontLists );
572 100 : ImplRefreshFontData( bNewFontLists );
573 100 : }
574 :
575 0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
576 : {
577 0 : ImplSVData* pSVData = ImplGetSVData();
578 :
579 0 : ImplUpdateFontDataForAllFrames( &OutputDevice::ImplClearFontData, bNewFontLists );
580 :
581 : // clear global font lists to have them updated
582 0 : pSVData->maGDIData.mpScreenFontCache->Invalidate();
583 0 : if ( bNewFontLists )
584 : {
585 0 : pSVData->maGDIData.mpScreenFontList->Clear();
586 0 : vcl::Window * pFrame = pSVData->maWinData.mpFirstFrame;
587 0 : if ( pFrame )
588 : {
589 0 : if ( pFrame->AcquireGraphics() )
590 : {
591 : // Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler
592 0 : OutputDevice *pDevice = (OutputDevice*)pFrame;
593 0 : pDevice->mpGraphics->ClearDevFontCache();
594 0 : pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontCollection);
595 : }
596 : }
597 : }
598 :
599 0 : ImplUpdateFontDataForAllFrames( &OutputDevice::ImplRefreshFontData, bNewFontLists );
600 0 : }
601 :
602 0 : void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists )
603 : {
604 0 : ImplSVData* const pSVData = ImplGetSVData();
605 :
606 : // update all windows
607 0 : vcl::Window* pFrame = pSVData->maWinData.mpFirstFrame;
608 0 : while ( pFrame )
609 : {
610 0 : ( pFrame->*pHdl )( bNewFontLists );
611 :
612 0 : vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
613 0 : while ( pSysWin )
614 : {
615 0 : ( pSysWin->*pHdl )( bNewFontLists );
616 0 : pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
617 : }
618 :
619 0 : pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
620 : }
621 :
622 : // update all virtual devices
623 0 : VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
624 0 : while ( pVirDev )
625 : {
626 0 : ( pVirDev->*pHdl )( bNewFontLists );
627 0 : pVirDev = pVirDev->mpNext;
628 : }
629 :
630 : // update all printers
631 0 : Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
632 0 : while ( pPrinter )
633 : {
634 0 : ( pPrinter->*pHdl )( bNewFontLists );
635 0 : pPrinter = pPrinter->mpNext;
636 : }
637 0 : }
638 :
639 160 : void OutputDevice::BeginFontSubstitution()
640 : {
641 160 : ImplSVData* pSVData = ImplGetSVData();
642 160 : pSVData->maGDIData.mbFontSubChanged = false;
643 160 : }
644 :
645 160 : void OutputDevice::EndFontSubstitution()
646 : {
647 160 : ImplSVData* pSVData = ImplGetSVData();
648 160 : if ( pSVData->maGDIData.mbFontSubChanged )
649 : {
650 0 : ImplUpdateAllFontData( false );
651 :
652 0 : Application* pApp = GetpApp();
653 0 : DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
654 0 : pApp->DataChanged( aDCEvt );
655 0 : Application::NotifyAllWindows( aDCEvt );
656 0 : pSVData->maGDIData.mbFontSubChanged = false;
657 : }
658 160 : }
659 :
660 0 : void OutputDevice::AddFontSubstitute( const OUString& rFontName,
661 : const OUString& rReplaceFontName,
662 : sal_uInt16 nFlags )
663 : {
664 0 : ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
665 0 : if( !rpSubst )
666 0 : rpSubst = new ImplDirectFontSubstitution();
667 0 : rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
668 0 : ImplGetSVData()->maGDIData.mbFontSubChanged = true;
669 0 : }
670 :
671 0 : void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName,
672 : const OUString& rSubstFontName, sal_uInt16 nFlags )
673 : {
674 0 : maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
675 0 : }
676 :
677 0 : ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName,
678 : const OUString& rSubstFontName, sal_uInt16 nSubstFlags )
679 : : maName( rFontName )
680 : , maReplaceName( rSubstFontName )
681 0 : , mnFlags( nSubstFlags )
682 : {
683 0 : maSearchName = GetEnglishSearchFontName( rFontName );
684 0 : maSearchReplaceName = GetEnglishSearchFontName( rSubstFontName );
685 0 : }
686 :
687 0 : void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
688 : {
689 0 : ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
690 0 : if( pSubst )
691 0 : pSubst->RemoveFontSubstitute( n );
692 0 : }
693 :
694 0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
695 : {
696 0 : FontSubstList::iterator it = maFontSubstList.begin();
697 0 : for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
698 0 : if( it != maFontSubstList.end() )
699 0 : maFontSubstList.erase( it );
700 0 : }
701 :
702 160 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
703 : {
704 160 : const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
705 160 : if( !pSubst )
706 160 : return 0;
707 0 : int nCount = pSubst->GetFontSubstituteCount();
708 0 : return (sal_uInt16)nCount;
709 : }
710 :
711 0 : bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName,
712 : const OUString& rSearchName, sal_uInt16 nFlags ) const
713 : {
714 : // TODO: get rid of O(N) searches
715 0 : FontSubstList::const_iterator it = maFontSubstList.begin();
716 0 : for(; it != maFontSubstList.end(); ++it )
717 : {
718 0 : const ImplFontSubstEntry& rEntry = *it;
719 0 : if( ((rEntry.mnFlags & nFlags) || !nFlags)
720 0 : && (rEntry.maSearchName == rSearchName) )
721 : {
722 0 : rSubstName = rEntry.maSearchReplaceName;
723 0 : return true;
724 : }
725 : }
726 :
727 0 : return false;
728 : }
729 :
730 24584 : void ImplFontSubstitute( OUString& rFontName )
731 : {
732 : // must be canonicalised
733 : assert( GetEnglishSearchFontName( rFontName ) == rFontName );
734 :
735 24584 : OUString aSubstFontName;
736 :
737 : // apply user-configurable font replacement (eg, from the list in Tools->Options)
738 24584 : const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
739 24584 : if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
740 : {
741 0 : rFontName = aSubstFontName;
742 24584 : return;
743 24584 : }
744 : }
745 :
746 : //hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl
747 298690 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
748 : sal_uLong nFlags, const OutputDevice* pOutDev )
749 : {
750 298690 : if (!pOutDev) // default is NULL
751 298690 : pOutDev = Application::GetDefaultDevice();
752 :
753 : LanguageTag aLanguageTag(
754 298658 : ( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW ) ?
755 1352 : Application::GetSettings().GetUILanguageTag() :
756 300042 : LanguageTag( eLang ));
757 :
758 298690 : utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
759 597380 : OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType );
760 597380 : OUString aSearch;
761 :
762 298690 : if( !aDefault.isEmpty() )
763 288472 : aSearch = aDefault;
764 : else
765 10218 : aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback
766 :
767 298690 : Font aFont;
768 298690 : aFont.SetPitch( PITCH_VARIABLE );
769 :
770 298690 : switch ( nType )
771 : {
772 : case DEFAULTFONT_SANS_UNICODE:
773 : case DEFAULTFONT_UI_SANS:
774 0 : aFont.SetFamily( FAMILY_SWISS );
775 0 : break;
776 :
777 : case DEFAULTFONT_SANS:
778 : case DEFAULTFONT_LATIN_HEADING:
779 : case DEFAULTFONT_LATIN_SPREADSHEET:
780 : case DEFAULTFONT_LATIN_DISPLAY:
781 13210 : aFont.SetFamily( FAMILY_SWISS );
782 13210 : break;
783 :
784 : case DEFAULTFONT_SERIF:
785 : case DEFAULTFONT_LATIN_TEXT:
786 : case DEFAULTFONT_LATIN_PRESENTATION:
787 87686 : aFont.SetFamily( FAMILY_ROMAN );
788 87686 : break;
789 :
790 : case DEFAULTFONT_FIXED:
791 : case DEFAULTFONT_LATIN_FIXED:
792 : case DEFAULTFONT_UI_FIXED:
793 1188 : aFont.SetPitch( PITCH_FIXED );
794 1188 : aFont.SetFamily( FAMILY_MODERN );
795 1188 : break;
796 :
797 : case DEFAULTFONT_SYMBOL:
798 0 : aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
799 0 : break;
800 :
801 : case DEFAULTFONT_CJK_TEXT:
802 : case DEFAULTFONT_CJK_PRESENTATION:
803 : case DEFAULTFONT_CJK_SPREADSHEET:
804 : case DEFAULTFONT_CJK_HEADING:
805 : case DEFAULTFONT_CJK_DISPLAY:
806 98302 : aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
807 98302 : break;
808 :
809 : case DEFAULTFONT_CTL_TEXT:
810 : case DEFAULTFONT_CTL_PRESENTATION:
811 : case DEFAULTFONT_CTL_SPREADSHEET:
812 : case DEFAULTFONT_CTL_HEADING:
813 : case DEFAULTFONT_CTL_DISPLAY:
814 98304 : aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
815 98304 : break;
816 : }
817 :
818 298690 : if ( !aSearch.isEmpty() )
819 : {
820 298690 : aFont.SetHeight( 12 ); // corresponds to nDefaultHeight
821 298690 : aFont.SetWeight( WEIGHT_NORMAL );
822 298690 : aFont.SetLanguage( eLang );
823 :
824 298690 : if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
825 298690 : aFont.SetCharSet( osl_getThreadTextEncoding() );
826 :
827 : // Should we only return available fonts on the given device
828 298690 : if ( pOutDev )
829 : {
830 298690 : pOutDev->ImplInitFontList();
831 :
832 : // Search Font in the FontList
833 298690 : OUString aName;
834 597380 : OUString aSearchName;
835 298690 : sal_Int32 nIndex = 0;
836 2006652 : do
837 : {
838 2117976 : aSearchName = GetEnglishSearchFontName( GetNextFontToken( aSearch, nIndex ) );
839 :
840 2117976 : PhysicalFontFamily* pFontFamily = pOutDev->mpFontCollection->ImplFindBySearchName( aSearchName );
841 2117976 : if( pFontFamily )
842 : {
843 114258 : AddTokenFontName( aName, pFontFamily->GetFamilyName() );
844 114258 : if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
845 111324 : break;
846 : }
847 : }
848 2006652 : while ( nIndex != -1 );
849 597380 : aFont.SetName( aName );
850 : }
851 :
852 : // No Name, than set all names
853 298690 : if ( aFont.GetName().isEmpty() )
854 : {
855 186388 : if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
856 : {
857 186388 : if( !pOutDev )
858 : {
859 : SAL_WARN ("vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here");
860 0 : sal_Int32 nIndex = 0;
861 0 : aFont.SetName( aSearch.getToken( 0, ';', nIndex ) );
862 : }
863 : else
864 : {
865 186388 : pOutDev->ImplInitFontList();
866 :
867 186388 : aFont.SetName( aSearch );
868 :
869 : // convert to pixel height
870 186388 : Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
871 186388 : if ( !aSize.Height() )
872 : {
873 : // use default pixel height only when logical height is zero
874 0 : if ( aFont.GetHeight() )
875 0 : aSize.Height() = 1;
876 : else
877 0 : aSize.Height() = (12*pOutDev->mnDPIY)/72;
878 : }
879 :
880 : // use default width only when logical width is zero
881 186388 : if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
882 0 : aSize.Width() = 1;
883 :
884 : // get the name of the first available font
885 186388 : float fExactHeight = static_cast<float>(aSize.Height());
886 186388 : ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontCollection, aFont, aSize, fExactHeight );
887 186388 : if (pEntry)
888 : {
889 186388 : if( pEntry->maFontSelData.mpFontData )
890 186388 : aFont.SetName( pEntry->maFontSelData.mpFontData->GetFamilyName() );
891 : else
892 0 : aFont.SetName( pEntry->maFontSelData.maTargetName );
893 : }
894 : }
895 : }
896 : else
897 0 : aFont.SetName( aSearch );
898 : }
899 : }
900 :
901 : #if OSL_DEBUG_LEVEL > 2
902 : const char* s = "DEFAULTFONT_SANS_UNKNOWN";
903 : switch ( nType )
904 : {
905 : case DEFAULTFONT_SANS_UNICODE: s = "DEFAULTFONT_SANS_UNICODE"; break;
906 : case DEFAULTFONT_UI_SANS: s = "DEFAULTFONT_UI_SANS"; break;
907 :
908 : case DEFAULTFONT_SANS: s = "DEFAULTFONT_SANS"; break;
909 : case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
910 : case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
911 : case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
912 :
913 : case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
914 : case DEFAULTFONT_LATIN_TEXT: s = "DEFAULTFONT_LATIN_TEXT"; break;
915 : case DEFAULTFONT_LATIN_PRESENTATION: s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
916 :
917 : case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
918 : case DEFAULTFONT_LATIN_FIXED: s = "DEFAULTFONT_LATIN_FIXED"; break;
919 : case DEFAULTFONT_UI_FIXED: s = "DEFAULTFONT_UI_FIXED"; break;
920 :
921 : case DEFAULTFONT_SYMBOL: s = "DEFAULTFONT_SYMBOL"; break;
922 :
923 : case DEFAULTFONT_CJK_TEXT: s = "DEFAULTFONT_CJK_TEXT"; break;
924 : case DEFAULTFONT_CJK_PRESENTATION: s = "DEFAULTFONT_CJK_PRESENTATION"; break;
925 : case DEFAULTFONT_CJK_SPREADSHEET: s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
926 : case DEFAULTFONT_CJK_HEADING: s = "DEFAULTFONT_CJK_HEADING"; break;
927 : case DEFAULTFONT_CJK_DISPLAY: s = "DEFAULTFONT_CJK_DISPLAY"; break;
928 :
929 : case DEFAULTFONT_CTL_TEXT: s = "DEFAULTFONT_CTL_TEXT"; break;
930 : case DEFAULTFONT_CTL_PRESENTATION: s = "DEFAULTFONT_CTL_PRESENTATION"; break;
931 : case DEFAULTFONT_CTL_SPREADSHEET: s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
932 : case DEFAULTFONT_CTL_HEADING: s = "DEFAULTFONT_CTL_HEADING"; break;
933 : case DEFAULTFONT_CTL_DISPLAY: s = "DEFAULTFONT_CTL_DISPLAY"; break;
934 : }
935 : fprintf( stderr, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
936 : s, eLang, nFlags,
937 : OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
938 : );
939 : #endif
940 :
941 597380 : return aFont;
942 : }
943 :
944 23884 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
945 : : maFontSelData( rFontSelData )
946 : , maMetric( rFontSelData )
947 : , mpConversion( NULL )
948 : , mnLineHeight( 0 )
949 : , mnRefCount( 1 )
950 : , mnSetFontFlags( 0 )
951 : , mnOwnOrientation( 0 )
952 : , mnOrientation( 0 )
953 : , mbInit( false )
954 23884 : , mpUnicodeFallbackList( NULL )
955 : {
956 23884 : maFontSelData.mpFontEntry = this;
957 23884 : }
958 :
959 46558 : ImplFontEntry::~ImplFontEntry()
960 : {
961 23279 : delete mpUnicodeFallbackList;
962 23279 : }
963 :
964 4962 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
965 : {
966 : boost::hash<sal_UCS4> a;
967 : boost::hash<int > b;
968 4962 : return a(rData.first) ^ b(rData.second);
969 : }
970 :
971 968 : void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
972 : {
973 968 : if( !mpUnicodeFallbackList )
974 182 : mpUnicodeFallbackList = new UnicodeFallbackList;
975 968 : (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
976 968 : }
977 :
978 3656 : bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const
979 : {
980 3656 : if( !mpUnicodeFallbackList )
981 364 : return false;
982 :
983 3292 : UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
984 3292 : if( it == mpUnicodeFallbackList->end() )
985 1182 : return false;
986 :
987 2110 : *pFontName = (*it).second;
988 2110 : return true;
989 : }
990 :
991 702 : void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
992 : {
993 : // DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
994 702 : UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
995 : // DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
996 702 : if( it == mpUnicodeFallbackList->end() )
997 702 : return;
998 702 : if( (*it).second == rFontName )
999 702 : mpUnicodeFallbackList->erase( it );
1000 : }
1001 :
1002 1081795 : FontSelectPatternAttributes::FontSelectPatternAttributes( const vcl::Font& rFont,
1003 : const OUString& rSearchName, const Size& rSize, float fExactHeight )
1004 : : maSearchName( rSearchName )
1005 1081795 : , mnWidth( rSize.Width() )
1006 1081795 : , mnHeight( rSize.Height() )
1007 : , mfExactHeight( fExactHeight)
1008 1081795 : , mnOrientation( rFont.GetOrientation() )
1009 1081795 : , meLanguage( rFont.GetLanguage() )
1010 1081795 : , mbVertical( rFont.IsVertical() )
1011 : , mbNonAntialiased( false )
1012 6490770 : , mbEmbolden( false )
1013 : {
1014 1081795 : maTargetName = GetFamilyName();
1015 :
1016 1081795 : rFont.GetFontAttributes( *this );
1017 :
1018 : // normalize orientation between 0 and 3600
1019 1081795 : if( 3600 <= (unsigned)mnOrientation )
1020 : {
1021 0 : if( mnOrientation >= 0 )
1022 0 : mnOrientation %= 3600;
1023 : else
1024 0 : mnOrientation = 3600 - (-mnOrientation % 3600);
1025 : }
1026 :
1027 : // normalize width and height
1028 1081795 : if( mnHeight < 0 )
1029 0 : mnHeight = -mnHeight;
1030 1081795 : if( mnWidth < 0 )
1031 0 : mnWidth = -mnWidth;
1032 1081795 : }
1033 :
1034 1081795 : FontSelectPattern::FontSelectPattern( const vcl::Font& rFont,
1035 : const OUString& rSearchName, const Size& rSize, float fExactHeight)
1036 : : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
1037 : , mpFontData( NULL )
1038 1081795 : , mpFontEntry( NULL )
1039 : {
1040 1081795 : }
1041 :
1042 : // NOTE: this ctor is still used on Windows. Do not remove.
1043 : #ifdef WNT
1044 : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
1045 : const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
1046 : : ImplFontAttributes( rFontData )
1047 : , mnWidth( rSize.Width() )
1048 : , mnHeight( rSize.Height() )
1049 : , mfExactHeight( fExactHeight )
1050 : , mnOrientation( nOrientation )
1051 : , meLanguage( 0 )
1052 : , mbVertical( bVertical )
1053 : , mbNonAntialiased( false )
1054 : , mbEmbolden( false )
1055 : {
1056 : maTargetName = maSearchName = GetFamilyName();
1057 : // NOTE: no normalization for width/height/orientation
1058 : }
1059 :
1060 : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
1061 : const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
1062 : : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
1063 : , mpFontData( &rFontData )
1064 : , mpFontEntry( NULL )
1065 : {
1066 : }
1067 : #endif
1068 :
1069 4401 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
1070 : {
1071 4401 : static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
1072 4401 : }
1073 :
1074 1134919 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
1075 : {
1076 1134919 : return rFSD.hashCode();
1077 : }
1078 :
1079 1134919 : size_t FontSelectPatternAttributes::hashCode() const
1080 : {
1081 : // TODO: does it pay off to improve this hash function?
1082 : size_t nHash;
1083 : #if ENABLE_GRAPHITE
1084 : // check for features and generate a unique hash if necessary
1085 1134919 : if (maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
1086 : != -1)
1087 : {
1088 0 : nHash = maTargetName.hashCode();
1089 : }
1090 : else
1091 : #endif
1092 : {
1093 1134919 : nHash = maSearchName.hashCode();
1094 : }
1095 1134919 : nHash += 11 * mnHeight;
1096 1134919 : nHash += 19 * GetWeight();
1097 1134919 : nHash += 29 * GetSlant();
1098 1134919 : nHash += 37 * mnOrientation;
1099 1134919 : nHash += 41 * meLanguage;
1100 1134919 : if( mbVertical )
1101 122 : nHash += 53;
1102 1134919 : return nHash;
1103 : }
1104 :
1105 92930 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
1106 : {
1107 92930 : if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
1108 71941 : return false;
1109 :
1110 20989 : if (maTargetName != rOther.maTargetName)
1111 0 : return false;
1112 :
1113 20989 : if (maSearchName != rOther.maSearchName)
1114 0 : return false;
1115 :
1116 20989 : if (mnWidth != rOther.mnWidth)
1117 1887 : return false;
1118 :
1119 19102 : if (mnHeight != rOther.mnHeight)
1120 13088 : return false;
1121 :
1122 6014 : if (mfExactHeight != rOther.mfExactHeight)
1123 18 : return false;
1124 :
1125 5996 : if (mnOrientation != rOther.mnOrientation)
1126 187 : return false;
1127 :
1128 5809 : if (meLanguage != rOther.meLanguage)
1129 1408 : return false;
1130 :
1131 4401 : if (mbVertical != rOther.mbVertical)
1132 0 : return false;
1133 :
1134 4401 : if (mbNonAntialiased != rOther.mbNonAntialiased)
1135 0 : return false;
1136 :
1137 4401 : if (mbEmbolden != rOther.mbEmbolden)
1138 0 : return false;
1139 :
1140 4401 : if (maItalicMatrix != rOther.maItalicMatrix)
1141 0 : return false;
1142 :
1143 4401 : return true;
1144 : }
1145 :
1146 2168818 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
1147 : {
1148 : // check normalized font family name
1149 2168818 : if( rA.maSearchName != rB.maSearchName )
1150 1079019 : return false;
1151 :
1152 : // check font transformation
1153 1089799 : if( (rA.mnHeight != rB.mnHeight)
1154 1089799 : || (rA.mnWidth != rB.mnWidth)
1155 1075595 : || (rA.mnOrientation != rB.mnOrientation) )
1156 14204 : return false;
1157 :
1158 : // check mapping relevant attributes
1159 1075595 : if( (rA.mbVertical != rB.mbVertical)
1160 1075595 : || (rA.meLanguage != rB.meLanguage) )
1161 0 : return false;
1162 :
1163 : // check font face attributes
1164 2151190 : if( (rA.GetWeight() != rB.GetWeight())
1165 1075595 : || (rA.GetSlant() != rB.GetSlant())
1166 : // || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member
1167 2151190 : || (rA.GetPitch() != rB.GetPitch()) )
1168 6782 : return false;
1169 :
1170 : // check style name
1171 1068813 : if( rA.GetStyleName() != rB.GetStyleName() )
1172 7030 : return false;
1173 :
1174 : // Symbol fonts may recode from one type to another So they are only
1175 : // safely equivalent for equal targets
1176 1061783 : if (
1177 1064303 : (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
1178 1144 : (rB.mpFontData && rB.mpFontData->IsSymbolFont())
1179 : )
1180 : {
1181 2520 : if (rA.maTargetName != rB.maTargetName)
1182 356 : return false;
1183 : }
1184 :
1185 : #if ENABLE_GRAPHITE
1186 : // check for features
1187 2122854 : if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
1188 1061427 : != -1 ||
1189 1061427 : rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
1190 1061427 : != -1) && rA.maTargetName != rB.maTargetName)
1191 0 : return false;
1192 : #endif
1193 :
1194 1061427 : if (rA.mbEmbolden != rB.mbEmbolden)
1195 0 : return false;
1196 :
1197 1061427 : if (rA.maItalicMatrix != rB.maItalicMatrix)
1198 0 : return false;
1199 :
1200 1061427 : return true;
1201 : }
1202 :
1203 7143 : ImplFontCache::ImplFontCache()
1204 : : mpFirstEntry( NULL ),
1205 7143 : mnRef0Count( 0 )
1206 7143 : {}
1207 :
1208 14190 : ImplFontCache::~ImplFontCache()
1209 : {
1210 7095 : FontInstanceList::iterator it = maFontInstanceList.begin();
1211 26674 : for(; it != maFontInstanceList.end(); ++it )
1212 : {
1213 19579 : ImplFontEntry* pEntry = (*it).second;
1214 19579 : delete pEntry;
1215 : }
1216 7095 : }
1217 :
1218 1081795 : ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList,
1219 : const vcl::Font& rFont, const Size& rSize, float fExactHeight )
1220 : {
1221 1081795 : OUString aSearchName = rFont.GetName();
1222 :
1223 : // initialize internal font request object
1224 2163590 : FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
1225 2163590 : return GetFontEntry( pFontList, aFontSelData );
1226 : }
1227 :
1228 1085311 : ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList,
1229 : FontSelectPattern& aFontSelData )
1230 : {
1231 1085311 : const FontSelectPattern aFontSelDataOrig(aFontSelData);
1232 : // check if a directly matching logical font instance is already cached,
1233 : // the most recently used font usually has a hit rate of >50%
1234 1085311 : ImplFontEntry *pEntry = NULL;
1235 1085311 : PhysicalFontFamily* pFontFamily = NULL;
1236 : IFSD_Equal aIFSD_Equal;
1237 1085311 : if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
1238 0 : pEntry = mpFirstEntry;
1239 : else
1240 : {
1241 1085311 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
1242 1085311 : if( it != maFontInstanceList.end() )
1243 1061427 : pEntry = (*it).second;
1244 : }
1245 :
1246 1085311 : if( !pEntry ) // no direct cache hit
1247 : {
1248 : // find the best matching logical font family and update font selector accordingly
1249 23884 : pFontFamily = pFontList->ImplFindByFont( aFontSelData );
1250 : DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
1251 23884 : if( pFontFamily )
1252 23884 : aFontSelData.maSearchName = pFontFamily->GetSearchName();
1253 :
1254 : // check if an indirectly matching logical font instance is already cached
1255 23884 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
1256 23884 : if( it != maFontInstanceList.end() )
1257 : {
1258 : // we have an indirect cache hit
1259 0 : pEntry = (*it).second;
1260 : }
1261 : }
1262 :
1263 1085311 : PhysicalFontFace* pFontData = NULL;
1264 :
1265 1085311 : if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
1266 : {
1267 23884 : bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
1268 23884 : pFontData = pFontFamily->FindBestFontFace( aFontSelData );
1269 23884 : aFontSelData.mpFontData = pFontData;
1270 23884 : bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
1271 :
1272 23884 : if (bNewIsSymbol != bOrigWasSymbol)
1273 : {
1274 : // it is possible, though generally unlikely, that at this point we
1275 : // will attempt to use a symbol font as a last-ditch fallback for a
1276 : // non-symbol font request or vice versa, and by changing
1277 : // aFontSelData.mpFontData to/from a symbol font we may now find
1278 : // something in the cache that can be reused which previously
1279 : // wasn't a candidate
1280 1840 : FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
1281 1840 : if( it != maFontInstanceList.end() )
1282 0 : pEntry = (*it).second;
1283 : }
1284 : }
1285 :
1286 1085311 : if( pEntry ) // cache hit => use existing font instance
1287 : {
1288 : // increase the font instance's reference count
1289 1061427 : if( !pEntry->mnRefCount++ )
1290 292746 : --mnRef0Count;
1291 : }
1292 :
1293 1085311 : if (!pEntry && pFontData)// still no cache hit => create a new font instance
1294 : {
1295 : // create a new logical font instance from this physical font face
1296 23884 : pEntry = pFontData->CreateFontInstance( aFontSelData );
1297 :
1298 : // if we're subtituting from or to a symbol font we may need a symbol
1299 : // conversion table
1300 23884 : if( pFontData->IsSymbolFont() || aFontSelData.IsSymbolFont() )
1301 : {
1302 1978 : if( aFontSelData.maTargetName != aFontSelData.maSearchName )
1303 1978 : pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
1304 : }
1305 :
1306 : #ifdef MACOSX
1307 : //It might be better to dig out the font version of the target font
1308 : //to see if it's a modern re-coded apple symbol font in case that
1309 : //font shows up on a different platform
1310 : if (!pEntry->mpConversion &&
1311 : aFontSelData.maTargetName.equalsIgnoreAsciiCase("symbol") &&
1312 : aFontSelData.maSearchName.equalsIgnoreAsciiCase("symbol"))
1313 : {
1314 : pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") );
1315 : }
1316 : #endif
1317 :
1318 : // Add the new entry to the cache with the original FontSelectPattern,
1319 : // so that we can find it next time as a direct cache hit.
1320 23884 : maFontInstanceList[ aFontSelDataOrig ] = pEntry;
1321 : }
1322 :
1323 1085311 : mpFirstEntry = pEntry;
1324 1085311 : return pEntry;
1325 : }
1326 :
1327 4744 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( PhysicalFontCollection* pFontCollection,
1328 : FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes )
1329 : {
1330 : // get a candidate font for glyph fallback
1331 : // unless the previously selected font got a device specific substitution
1332 : // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
1333 4744 : if( nFallbackLevel >= 1)
1334 : {
1335 4744 : PhysicalFontFamily* pFallbackData = NULL;
1336 :
1337 : //fdo#33898 If someone has EUDC installed then they really want that to
1338 : //be used as the first-choice glyph fallback seeing as it's filled with
1339 : //private area codes with don't make any sense in any other font so
1340 : //prioritise it here if it's available. Ideally we would remove from
1341 : //rMissingCodes all the glyphs which it is able to resolve as an
1342 : //optimization, but that's tricky to achieve cross-platform without
1343 : //sufficient heavy-weight code that's likely to undo the value of the
1344 : //optimization
1345 4744 : if (nFallbackLevel == 1)
1346 1938 : pFallbackData = pFontCollection->FindFontFamily(OUString("EUDC"));
1347 4744 : if (!pFallbackData)
1348 4744 : pFallbackData = pFontCollection->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
1349 : // escape when there are no font candidates
1350 4744 : if( !pFallbackData )
1351 1228 : return NULL;
1352 : // override the font name
1353 3516 : rFontSelData.SetFamilyName( pFallbackData->GetFamilyName() );
1354 : // clear the cached normalized name
1355 3516 : rFontSelData.maSearchName = "";
1356 : }
1357 :
1358 3516 : ImplFontEntry* pFallbackFont = GetFontEntry( pFontCollection, rFontSelData );
1359 3516 : return pFallbackFont;
1360 : }
1361 :
1362 898476 : void ImplFontCache::Release( ImplFontEntry* pEntry )
1363 : {
1364 : static const int FONTCACHE_MAX = 50;
1365 :
1366 : DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
1367 898476 : if( --pEntry->mnRefCount > 0 )
1368 1481171 : return;
1369 :
1370 315707 : if( ++mnRef0Count < FONTCACHE_MAX )
1371 315633 : return;
1372 :
1373 : // remove unused entries from font instance cache
1374 74 : FontInstanceList::iterator it_next = maFontInstanceList.begin();
1375 4324 : while( it_next != maFontInstanceList.end() )
1376 : {
1377 4176 : FontInstanceList::iterator it = it_next++;
1378 4176 : ImplFontEntry* pFontEntry = (*it).second;
1379 4176 : if( pFontEntry->mnRefCount > 0 )
1380 476 : continue;
1381 :
1382 3700 : maFontInstanceList.erase( it );
1383 3700 : delete pFontEntry;
1384 3700 : --mnRef0Count;
1385 : DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
1386 :
1387 3700 : if( mpFirstEntry == pFontEntry )
1388 31 : mpFirstEntry = NULL;
1389 : }
1390 :
1391 : DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
1392 : }
1393 :
1394 100 : void ImplFontCache::Invalidate()
1395 : {
1396 : // delete unreferenced entries
1397 100 : FontInstanceList::iterator it = maFontInstanceList.begin();
1398 100 : for(; it != maFontInstanceList.end(); ++it )
1399 : {
1400 0 : ImplFontEntry* pFontEntry = (*it).second;
1401 0 : if( pFontEntry->mnRefCount > 0 )
1402 0 : continue;
1403 :
1404 0 : delete pFontEntry;
1405 0 : --mnRef0Count;
1406 : }
1407 :
1408 : // #112304# make sure the font cache is really clean
1409 100 : mpFirstEntry = NULL;
1410 100 : maFontInstanceList.clear();
1411 :
1412 : DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
1413 100 : }
1414 :
1415 3056000 : void OutputDevice::ImplInitFontList() const
1416 : {
1417 3056000 : if( !mpFontCollection->Count() )
1418 : {
1419 312 : if( mpGraphics || AcquireGraphics() )
1420 : {
1421 : SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" );
1422 312 : mpGraphics->GetDevFontList( mpFontCollection );
1423 :
1424 : // There is absolutely no way there should be no fonts available on the device
1425 312 : if( !mpFontCollection->Count() )
1426 : {
1427 0 : OUString aError( "Application error: no fonts and no vcl resource found on your system" );
1428 0 : ResMgr* pMgr = ImplGetResMgr();
1429 0 : if( pMgr )
1430 : {
1431 0 : OUString aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
1432 0 : if( !aResStr.isEmpty() )
1433 0 : aError = aResStr;
1434 : }
1435 0 : Application::Abort( aError );
1436 : }
1437 : }
1438 : }
1439 3056000 : }
1440 :
1441 289719 : void OutputDevice::InitFont() const
1442 : {
1443 : DBG_TESTSOLARMUTEX();
1444 :
1445 289719 : if (!mpFontEntry)
1446 289719 : return;
1447 :
1448 289719 : if ( mbInitFont )
1449 : {
1450 : // decide if antialiasing is appropriate
1451 289719 : bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
1452 289719 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1453 289719 : bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
1454 289719 : bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
1455 289719 : mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
1456 :
1457 : // select font in the device layers
1458 289719 : mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
1459 289719 : mbInitFont = false;
1460 : }
1461 : }
1462 :
1463 1344787 : bool OutputDevice::ImplNewFont() const
1464 : {
1465 : DBG_TESTSOLARMUTEX();
1466 :
1467 : // get correct font list on the PDF writer if necessary
1468 1344787 : if( mpPDFWriter )
1469 : {
1470 0 : const ImplSVData* pSVData = ImplGetSVData();
1471 0 : if( mpFontCollection == pSVData->maGDIData.mpScreenFontList
1472 0 : || mpFontCache == pSVData->maGDIData.mpScreenFontCache )
1473 0 : const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
1474 : }
1475 :
1476 1344787 : if ( !mbNewFont )
1477 450067 : return true;
1478 :
1479 : // we need a graphics
1480 894720 : if ( !mpGraphics && !AcquireGraphics() )
1481 0 : return false;
1482 894720 : SalGraphics* pGraphics = mpGraphics;
1483 894720 : ImplInitFontList();
1484 :
1485 : // convert to pixel height
1486 : // TODO: replace integer based aSize completely with subpixel accurate type
1487 894720 : float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
1488 894720 : Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
1489 894720 : if ( !aSize.Height() )
1490 : {
1491 : // use default pixel height only when logical height is zero
1492 125 : if ( maFont.GetSize().Height() )
1493 0 : aSize.Height() = 1;
1494 : else
1495 125 : aSize.Height() = (12*mnDPIY)/72;
1496 125 : fExactHeight = static_cast<float>(aSize.Height());
1497 : }
1498 :
1499 : // select the default width only when logical width is zero
1500 894720 : if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
1501 0 : aSize.Width() = 1;
1502 :
1503 : // get font entry
1504 894720 : ImplFontEntry* pOldEntry = mpFontEntry;
1505 894720 : mpFontEntry = mpFontCache->GetFontEntry( mpFontCollection, maFont, aSize, fExactHeight );
1506 894720 : if( pOldEntry )
1507 739436 : mpFontCache->Release( pOldEntry );
1508 :
1509 894720 : ImplFontEntry* pFontEntry = mpFontEntry;
1510 :
1511 894720 : if (!pFontEntry)
1512 0 : return false;
1513 :
1514 : // mark when lower layers need to get involved
1515 894720 : mbNewFont = false;
1516 894720 : if( pFontEntry != pOldEntry )
1517 443254 : mbInitFont = true;
1518 :
1519 : // select font when it has not been initialized yet
1520 894720 : if ( !pFontEntry->mbInit )
1521 : {
1522 22771 : InitFont();
1523 :
1524 : // get metric data from device layers
1525 22771 : if ( pGraphics )
1526 : {
1527 22771 : pFontEntry->mbInit = true;
1528 :
1529 22771 : pFontEntry->maMetric.mnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
1530 22771 : pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
1531 :
1532 22771 : pFontEntry->maMetric.ImplInitTextLineSize( this );
1533 22771 : pFontEntry->maMetric.ImplInitAboveTextLineSize();
1534 :
1535 22771 : pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
1536 :
1537 22771 : SetFontOrientation( pFontEntry );
1538 : }
1539 : }
1540 :
1541 : // enable kerning array if requested
1542 894720 : if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
1543 : {
1544 : // TODO: test if physical font supports kerning and disable if not
1545 297594 : if( pFontEntry->maMetric.mbKernableFont )
1546 201458 : mbKerning = true;
1547 : }
1548 : else
1549 597126 : mbKerning = false;
1550 894720 : if ( maFont.GetKerning() & KERNING_ASIAN )
1551 0 : mbKerning = true;
1552 :
1553 : // calculate EmphasisArea
1554 894720 : mnEmphasisAscent = 0;
1555 894720 : mnEmphasisDescent = 0;
1556 894720 : if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
1557 : {
1558 55653 : FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
1559 55653 : long nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
1560 55653 : if ( nEmphasisHeight < 1 )
1561 9 : nEmphasisHeight = 1;
1562 55653 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
1563 12 : mnEmphasisDescent = nEmphasisHeight;
1564 : else
1565 55641 : mnEmphasisAscent = nEmphasisHeight;
1566 : }
1567 :
1568 : // calculate text offset depending on TextAlignment
1569 894720 : TextAlign eAlign = maFont.GetAlign();
1570 894720 : if ( eAlign == ALIGN_BASELINE )
1571 : {
1572 709069 : mnTextOffX = 0;
1573 709069 : mnTextOffY = 0;
1574 : }
1575 185651 : else if ( eAlign == ALIGN_TOP )
1576 : {
1577 181974 : mnTextOffX = 0;
1578 181974 : mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
1579 181974 : if ( pFontEntry->mnOrientation )
1580 : {
1581 20140 : Point aOriginPt(0, 0);
1582 20140 : aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
1583 : }
1584 : }
1585 : else // eAlign == ALIGN_BOTTOM
1586 : {
1587 3677 : mnTextOffX = 0;
1588 3677 : mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
1589 3677 : if ( pFontEntry->mnOrientation )
1590 : {
1591 0 : Point aOriginPt(0, 0);
1592 0 : aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
1593 : }
1594 : }
1595 :
1596 1795291 : mbTextLines = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
1597 2625682 : ((maFont.GetOverline() != UNDERLINE_NONE) && (maFont.GetOverline() != UNDERLINE_DONTKNOW)) ||
1598 1719212 : ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
1599 1753538 : mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() ||
1600 1753538 : (maFont.GetRelief() != RELIEF_NONE);
1601 :
1602 :
1603 : // #95414# fix for OLE objects which use scale factors very creatively
1604 894720 : if( mbMap && !aSize.Width() )
1605 : {
1606 683008 : int nOrigWidth = pFontEntry->maMetric.mnWidth;
1607 683008 : float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
1608 683008 : fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
1609 683008 : int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
1610 683008 : if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
1611 : {
1612 214 : Size aOrigSize = maFont.GetSize();
1613 214 : const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
1614 214 : mbMap = false;
1615 214 : mbNewFont = true;
1616 214 : ImplNewFont(); // recurse once using stretched width
1617 214 : mbMap = true;
1618 214 : const_cast<Font&>(maFont).SetSize( aOrigSize );
1619 : }
1620 : }
1621 :
1622 894720 : return true;
1623 : }
1624 :
1625 22286 : void OutputDevice::SetFontOrientation( ImplFontEntry* const pFontEntry ) const
1626 : {
1627 22286 : if( pFontEntry->maFontSelData.mnOrientation && !pFontEntry->maMetric.mnOrientation )
1628 : {
1629 0 : pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
1630 0 : pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
1631 : }
1632 : else
1633 : {
1634 22286 : pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
1635 : }
1636 22286 : }
1637 :
1638 92930 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
1639 : {
1640 92930 : if (maName != rOther.maName)
1641 49189 : return false;
1642 :
1643 43741 : if (maStyleName != rOther.maStyleName)
1644 1264 : return false;
1645 :
1646 42477 : if (meWeight != rOther.meWeight)
1647 12661 : return false;
1648 :
1649 29816 : if (meItalic != rOther.meItalic)
1650 3447 : return false;
1651 :
1652 26369 : if (meFamily != rOther.meFamily)
1653 4007 : return false;
1654 :
1655 22362 : if (mePitch != rOther.mePitch)
1656 1373 : return false;
1657 :
1658 20989 : if (meWidthType != rOther.meWidthType)
1659 0 : return false;
1660 :
1661 20989 : if (mbSymbolFlag != rOther.mbSymbolFlag)
1662 0 : return false;
1663 :
1664 20989 : return true;
1665 : }
1666 :
1667 23884 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
1668 : : ImplFontAttributes( rFontSelData )
1669 : , mnWidth ( rFontSelData.mnWidth)
1670 : , mnOrientation( (short)(rFontSelData.mnOrientation))
1671 : , mnAscent( 0 )
1672 : , mnDescent( 0 )
1673 : , mnIntLeading( 0 )
1674 : , mnExtLeading( 0 )
1675 : , mnSlant( 0 )
1676 : , mnMinKashida( 0 )
1677 : , meFamilyType(FAMILY_DONTKNOW)
1678 : , mbScalableFont(false)
1679 : , mnUnderlineSize( 0 )
1680 : , mnUnderlineOffset( 0 )
1681 : , mnBUnderlineSize( 0 )
1682 : , mnBUnderlineOffset( 0 )
1683 : , mnDUnderlineSize( 0 )
1684 : , mnDUnderlineOffset1( 0 )
1685 : , mnDUnderlineOffset2( 0 )
1686 : , mnWUnderlineSize( 0 )
1687 : , mnWUnderlineOffset( 0 )
1688 : , mnAboveUnderlineSize( 0 )
1689 : , mnAboveUnderlineOffset( 0 )
1690 : , mnAboveBUnderlineSize( 0 )
1691 : , mnAboveBUnderlineOffset( 0 )
1692 : , mnAboveDUnderlineSize( 0 )
1693 : , mnAboveDUnderlineOffset1( 0 )
1694 : , mnAboveDUnderlineOffset2( 0 )
1695 : , mnAboveWUnderlineSize( 0 )
1696 : , mnAboveWUnderlineOffset( 0 )
1697 : , mnStrikeoutSize( 0 )
1698 : , mnStrikeoutOffset( 0 )
1699 : , mnBStrikeoutSize( 0 )
1700 : , mnBStrikeoutOffset( 0 )
1701 : , mnDStrikeoutSize( 0 )
1702 : , mnDStrikeoutOffset1( 0 )
1703 23884 : , mnDStrikeoutOffset2( 0 )
1704 : {
1705 : // intialize the used font name
1706 23884 : if( rFontSelData.mpFontData )
1707 : {
1708 23884 : SetFamilyName( rFontSelData.mpFontData->GetFamilyName() );
1709 23884 : SetStyleName( rFontSelData.mpFontData->GetStyleName() );
1710 23884 : mbDevice = rFontSelData.mpFontData->mbDevice;
1711 23884 : mbKernableFont = true;
1712 : }
1713 : else
1714 : {
1715 0 : sal_Int32 nTokenPos = 0;
1716 0 : SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) );
1717 0 : SetStyleName( rFontSelData.GetStyleName() );
1718 0 : mbDevice = false;
1719 0 : mbKernableFont = false;
1720 : }
1721 23884 : }
1722 :
1723 22771 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
1724 : {
1725 22771 : long nDescent = mnDescent;
1726 22771 : if ( nDescent <= 0 )
1727 : {
1728 9 : nDescent = mnAscent / 10;
1729 9 : if ( !nDescent )
1730 9 : nDescent = 1;
1731 : }
1732 :
1733 : // #i55341# for some fonts it is not a good idea to calculate
1734 : // their text line metrics from the real font descent
1735 : // => work around this problem just for these fonts
1736 22771 : if( 3*nDescent > mnAscent )
1737 2343 : nDescent = mnAscent / 3;
1738 :
1739 22771 : long nLineHeight = ((nDescent*25)+50) / 100;
1740 22771 : if ( !nLineHeight )
1741 199 : nLineHeight = 1;
1742 22771 : long nLineHeight2 = nLineHeight / 2;
1743 22771 : if ( !nLineHeight2 )
1744 3735 : nLineHeight2 = 1;
1745 :
1746 22771 : long nBLineHeight = ((nDescent*50)+50) / 100;
1747 22771 : if ( nBLineHeight == nLineHeight )
1748 1006 : nBLineHeight++;
1749 22771 : long nBLineHeight2 = nBLineHeight/2;
1750 22771 : if ( !nBLineHeight2 )
1751 27 : nBLineHeight2 = 1;
1752 :
1753 22771 : long n2LineHeight = ((nDescent*16)+50) / 100;
1754 22771 : if ( !n2LineHeight )
1755 2969 : n2LineHeight = 1;
1756 22771 : long n2LineDY = n2LineHeight;
1757 : /* #117909#
1758 : * add some pixels to minimum double line distance on higher resolution devices
1759 : */
1760 22771 : long nMin2LineDY = 1 + pDev->GetDPIY()/150;
1761 22771 : if ( n2LineDY < nMin2LineDY )
1762 12386 : n2LineDY = nMin2LineDY;
1763 22771 : long n2LineDY2 = n2LineDY/2;
1764 22771 : if ( !n2LineDY2 )
1765 4400 : n2LineDY2 = 1;
1766 :
1767 22771 : long nUnderlineOffset = mnDescent/2 + 1;
1768 22771 : long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
1769 :
1770 22771 : mnUnderlineSize = nLineHeight;
1771 22771 : mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
1772 :
1773 22771 : mnBUnderlineSize = nBLineHeight;
1774 22771 : mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
1775 :
1776 22771 : mnDUnderlineSize = n2LineHeight;
1777 22771 : mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
1778 22771 : mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
1779 :
1780 22771 : long nWCalcSize = mnDescent;
1781 22771 : if ( nWCalcSize < 6 )
1782 : {
1783 3709 : if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
1784 1000 : mnWUnderlineSize = nWCalcSize;
1785 : else
1786 2709 : mnWUnderlineSize = 3;
1787 : }
1788 : else
1789 19062 : mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
1790 :
1791 : // #109280# the following line assures that wavelnes are never placed below the descent, however
1792 : // for most fonts the waveline then is drawn into the text, so we better keep the old solution
1793 : // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
1794 22771 : mnWUnderlineOffset = nUnderlineOffset;
1795 :
1796 22771 : mnStrikeoutSize = nLineHeight;
1797 22771 : mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
1798 :
1799 22771 : mnBStrikeoutSize = nBLineHeight;
1800 22771 : mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
1801 :
1802 22771 : mnDStrikeoutSize = n2LineHeight;
1803 22771 : mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
1804 22771 : mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
1805 22771 : }
1806 :
1807 22771 : void ImplFontMetricData::ImplInitAboveTextLineSize()
1808 : {
1809 22771 : long nIntLeading = mnIntLeading;
1810 : // TODO: assess usage of nLeading below (changed in extleading CWS)
1811 : // if no leading is available, we assume 15% of the ascent
1812 22771 : if ( nIntLeading <= 0 )
1813 : {
1814 6133 : nIntLeading = mnAscent*15/100;
1815 6133 : if ( !nIntLeading )
1816 227 : nIntLeading = 1;
1817 : }
1818 :
1819 22771 : long nLineHeight = ((nIntLeading*25)+50) / 100;
1820 22771 : if ( !nLineHeight )
1821 2618 : nLineHeight = 1;
1822 :
1823 22771 : long nBLineHeight = ((nIntLeading*50)+50) / 100;
1824 22771 : if ( nBLineHeight == nLineHeight )
1825 3774 : nBLineHeight++;
1826 :
1827 22771 : long n2LineHeight = ((nIntLeading*16)+50) / 100;
1828 22771 : if ( !n2LineHeight )
1829 4265 : n2LineHeight = 1;
1830 :
1831 22771 : long nCeiling = -mnAscent;
1832 :
1833 22771 : mnAboveUnderlineSize = nLineHeight;
1834 22771 : mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
1835 :
1836 22771 : mnAboveBUnderlineSize = nBLineHeight;
1837 22771 : mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
1838 :
1839 22771 : mnAboveDUnderlineSize = n2LineHeight;
1840 22771 : mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
1841 22771 : mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2;
1842 :
1843 22771 : long nWCalcSize = nIntLeading;
1844 22771 : if ( nWCalcSize < 6 )
1845 : {
1846 5555 : if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
1847 3774 : mnAboveWUnderlineSize = nWCalcSize;
1848 : else
1849 1781 : mnAboveWUnderlineSize = 3;
1850 : }
1851 : else
1852 17216 : mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
1853 :
1854 22771 : mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
1855 22771 : }
1856 :
1857 35178 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
1858 : const tools::PolyPolygon& rPolyPoly, bool bPolyLine,
1859 : const Rectangle& rRect1, const Rectangle& rRect2 )
1860 : {
1861 35178 : if( IsRTLEnabled() )
1862 : // --- RTL --- mirror at basex
1863 668 : nX = nBaseX - (nX - nBaseX - 1);
1864 :
1865 35178 : nX -= mnOutOffX;
1866 35178 : nY -= mnOutOffY;
1867 :
1868 35178 : if ( rPolyPoly.Count() )
1869 : {
1870 29224 : if ( bPolyLine )
1871 : {
1872 10442 : Polygon aPoly = rPolyPoly.GetObject( 0 );
1873 10442 : aPoly.Move( nX, nY );
1874 10442 : DrawPolyLine( aPoly );
1875 : }
1876 : else
1877 : {
1878 18782 : tools::PolyPolygon aPolyPoly = rPolyPoly;
1879 18782 : aPolyPoly.Move( nX, nY );
1880 18782 : DrawPolyPolygon( aPolyPoly );
1881 : }
1882 : }
1883 :
1884 35178 : if ( !rRect1.IsEmpty() )
1885 : {
1886 5954 : Rectangle aRect( Point( nX+rRect1.Left(),
1887 11908 : nY+rRect1.Top() ), rRect1.GetSize() );
1888 5954 : DrawRect( aRect );
1889 : }
1890 :
1891 35178 : if ( !rRect2.IsEmpty() )
1892 : {
1893 0 : Rectangle aRect( Point( nX+rRect2.Left(),
1894 0 : nY+rRect2.Top() ), rRect2.GetSize() );
1895 :
1896 0 : DrawRect( aRect );
1897 : }
1898 35178 : }
1899 :
1900 10674 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
1901 : {
1902 10674 : Color aOldLineColor = GetLineColor();
1903 10674 : Color aOldFillColor = GetFillColor();
1904 10674 : bool bOldMap = mbMap;
1905 10674 : GDIMetaFile* pOldMetaFile = mpMetaFile;
1906 10674 : mpMetaFile = NULL;
1907 10674 : EnableMapMode( false );
1908 :
1909 10674 : FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
1910 10674 : tools::PolyPolygon aPolyPoly;
1911 10674 : Rectangle aRect1;
1912 10674 : Rectangle aRect2;
1913 : long nEmphasisYOff;
1914 : long nEmphasisWidth;
1915 : long nEmphasisHeight;
1916 : bool bPolyLine;
1917 :
1918 10674 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
1919 0 : nEmphasisHeight = mnEmphasisDescent;
1920 : else
1921 10674 : nEmphasisHeight = mnEmphasisAscent;
1922 :
1923 : ImplGetEmphasisMark( aPolyPoly, bPolyLine,
1924 : aRect1, aRect2,
1925 : nEmphasisYOff, nEmphasisWidth,
1926 : nEmphasisMark,
1927 10674 : nEmphasisHeight, mpFontEntry->mnOrientation );
1928 :
1929 10674 : if ( bPolyLine )
1930 : {
1931 2816 : SetLineColor( GetTextColor() );
1932 2816 : SetFillColor();
1933 : }
1934 : else
1935 : {
1936 7858 : SetLineColor();
1937 7858 : SetFillColor( GetTextColor() );
1938 : }
1939 :
1940 10674 : Point aOffset = Point(0,0);
1941 :
1942 10674 : if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
1943 0 : aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
1944 : else
1945 10674 : aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
1946 :
1947 10674 : long nEmphasisWidth2 = nEmphasisWidth / 2;
1948 10674 : long nEmphasisHeight2 = nEmphasisHeight / 2;
1949 10674 : aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
1950 :
1951 10674 : Point aOutPoint;
1952 10674 : Rectangle aRectangle;
1953 10674 : for( int nStart = 0;;)
1954 : {
1955 : sal_GlyphId aGlyphId;
1956 47524 : if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aOutPoint, nStart ) )
1957 10674 : break;
1958 :
1959 36850 : if( !mpGraphics->GetGlyphBoundRect( aGlyphId, aRectangle ) )
1960 0 : continue;
1961 :
1962 36850 : if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
1963 : {
1964 35178 : Point aAdjPoint = aOffset;
1965 35178 : aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
1966 35178 : if ( mpFontEntry->mnOrientation )
1967 : {
1968 24474 : Point aOriginPt(0, 0);
1969 24474 : aOriginPt.RotateAround( aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
1970 : }
1971 35178 : aOutPoint += aAdjPoint;
1972 35178 : aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
1973 35178 : ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
1974 70356 : aOutPoint.X(), aOutPoint.Y(),
1975 140712 : aPolyPoly, bPolyLine, aRect1, aRect2 );
1976 : }
1977 36850 : }
1978 :
1979 10674 : SetLineColor( aOldLineColor );
1980 10674 : SetFillColor( aOldFillColor );
1981 10674 : EnableMapMode( bOldMap );
1982 10674 : mpMetaFile = pOldMetaFile;
1983 10674 : }
1984 :
1985 722 : SalLayout* OutputDevice::getFallbackFont(ImplFontEntry &rFallbackFont,
1986 : FontSelectPattern &rFontSelData, int nFallbackLevel,
1987 : ImplLayoutArgs& rLayoutArgs) const
1988 : {
1989 722 : rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
1990 :
1991 722 : rLayoutArgs.ResetPos();
1992 722 : SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
1993 :
1994 722 : if (!pFallback)
1995 0 : return NULL;
1996 :
1997 722 : if (!pFallback->LayoutText(rLayoutArgs))
1998 : {
1999 : // there is no need for a font that couldn't resolve anything
2000 0 : pFallback->Release();
2001 0 : return NULL;
2002 : }
2003 :
2004 722 : pFallback->AdjustLayout( rLayoutArgs );
2005 :
2006 722 : return pFallback;
2007 : }
2008 :
2009 1938 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
2010 : {
2011 : // This function relies on a valid mpFontEntry, if it doesn't exist bail out
2012 : // - we'd have crashed later on anyway. At least here we can catch the error in debug
2013 : // mode.
2014 1938 : if ( !mpFontEntry )
2015 : {
2016 : SAL_WARN ("vcl.gdi", "No font entry set in OutputDevice");
2017 : assert(mpFontEntry);
2018 0 : return NULL;
2019 : }
2020 :
2021 : // prepare multi level glyph fallback
2022 1938 : MultiSalLayout* pMultiSalLayout = NULL;
2023 1938 : ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
2024 1938 : rLayoutArgs.PrepareFallback();
2025 1938 : rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
2026 :
2027 : // get list of unicodes that need glyph fallback
2028 1938 : int nCharPos = -1;
2029 1938 : bool bRTL = false;
2030 3876 : OUStringBuffer aMissingCodeBuf;
2031 6116 : while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
2032 2240 : aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
2033 1938 : rLayoutArgs.ResetPos();
2034 3876 : OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
2035 :
2036 3876 : FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
2037 :
2038 : // try if fallback fonts support the missing unicodes
2039 4766 : for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
2040 : {
2041 : // find a font family suited for glyph fallback
2042 : #ifndef FONTFALLBACK_HOOKS_DISABLED
2043 : // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
2044 : // if the system-specific glyph fallback is active
2045 4744 : aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
2046 : #endif
2047 : ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontCollection,
2048 4744 : aFontSelData, nFallbackLevel, aMissingCodes );
2049 4744 : if( !pFallbackFont )
2050 1228 : break;
2051 :
2052 3516 : aFontSelData.mpFontEntry = pFallbackFont;
2053 3516 : aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
2054 3516 : if( nFallbackLevel < MAX_FALLBACK-1)
2055 : {
2056 : // ignore fallback font if it is the same as the original font
2057 3494 : if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
2058 : {
2059 2794 : mpFontCache->Release( pFallbackFont );
2060 2794 : continue;
2061 : }
2062 : }
2063 :
2064 : // create and add glyph fallback layout to multilayout
2065 : SalLayout* pFallback = getFallbackFont(*pFallbackFont, aFontSelData,
2066 722 : nFallbackLevel, rLayoutArgs);
2067 722 : if (pFallback)
2068 : {
2069 722 : if( !pMultiSalLayout )
2070 714 : pMultiSalLayout = new MultiSalLayout( *pSalLayout );
2071 : pMultiSalLayout->AddFallback( *pFallback,
2072 722 : rLayoutArgs.maRuns, aFontSelData.mpFontData );
2073 722 : if (nFallbackLevel == MAX_FALLBACK-1)
2074 22 : pMultiSalLayout->SetInComplete();
2075 : }
2076 :
2077 722 : mpFontCache->Release( pFallbackFont );
2078 :
2079 : // break when this fallback was sufficient
2080 722 : if( !rLayoutArgs.PrepareFallback() )
2081 688 : break;
2082 : }
2083 :
2084 1938 : if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
2085 714 : pSalLayout = pMultiSalLayout;
2086 :
2087 : // restore orig font settings
2088 1938 : pSalLayout->InitFont();
2089 1938 : rLayoutArgs.maRuns = aLayoutRuns;
2090 :
2091 3876 : return pSalLayout;
2092 : }
2093 :
2094 0 : long OutputDevice::GetMinKashida() const
2095 : {
2096 0 : if( mbNewFont && !ImplNewFont() )
2097 0 : return 0;
2098 :
2099 0 : ImplFontEntry* pEntry = mpFontEntry;
2100 0 : ImplFontMetricData* pMetric = &(pEntry->maMetric);
2101 0 : return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
2102 : }
2103 :
2104 0 : sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt,
2105 : sal_Int32 nIdx, sal_Int32 nLen,
2106 : sal_Int32 nKashCount,
2107 : const sal_Int32* pKashidaPos,
2108 : sal_Int32* pKashidaPosDropped ) const
2109 : {
2110 : // do layout
2111 0 : SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
2112 0 : if( !pSalLayout )
2113 0 : return 0;
2114 0 : sal_Int32 nDropped = 0;
2115 0 : for( int i = 0; i < nKashCount; ++i )
2116 : {
2117 0 : if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
2118 : {
2119 0 : pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
2120 0 : ++nDropped;
2121 : }
2122 : }
2123 0 : pSalLayout->Release();
2124 0 : return nDropped;
2125 : }
2126 :
2127 4974 : bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr,
2128 : int nIndex, int nLen, int nBase, MetricVector& rVector )
2129 : {
2130 :
2131 4974 : rVector.clear();
2132 :
2133 4974 : if(nLen == 0x0FFFF)
2134 : {
2135 : SAL_INFO("sal.rtl.xub",
2136 : "GetGlyphBoundRects Suspicious arguments nLen:" << nLen);
2137 : }
2138 :
2139 4974 : if( nIndex >= rStr.getLength() )
2140 2870 : return false;
2141 :
2142 2104 : if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
2143 : {
2144 2104 : nLen = rStr.getLength() - nIndex;
2145 : }
2146 :
2147 2104 : Rectangle aRect;
2148 28018 : for( int i = 0; i < nLen; i++ )
2149 : {
2150 25914 : if( !GetTextBoundRect( aRect, rStr, nBase, nIndex + i, 1 ) )
2151 0 : break;
2152 25914 : aRect.Move( rOrigin.X(), rOrigin.Y() );
2153 25914 : rVector.push_back( aRect );
2154 : }
2155 :
2156 2104 : return (nLen == (int)rVector.size());
2157 : }
2158 :
2159 11114 : sal_Int32 OutputDevice::HasGlyphs( const vcl::Font& rTempFont, const OUString& rStr,
2160 : sal_Int32 nIndex, sal_Int32 nLen ) const
2161 : {
2162 11114 : if( nIndex >= rStr.getLength() )
2163 0 : return nIndex;
2164 : sal_Int32 nEnd;
2165 11114 : if( nLen == -1 )
2166 11114 : nEnd = rStr.getLength();
2167 : else
2168 0 : nEnd = std::min( rStr.getLength(), nIndex + nLen );
2169 :
2170 : DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
2171 : DBG_ASSERT( nEnd <= rStr.getLength(), "String too short" );
2172 :
2173 : // to get the map temporarily set font
2174 11114 : const vcl::Font aOrigFont = GetFont();
2175 11114 : const_cast<OutputDevice&>(*this).SetFont( rTempFont );
2176 22228 : FontCharMapPtr pFontCharMap ( new FontCharMap() );
2177 11114 : bool bRet = GetFontCharMap( pFontCharMap );
2178 11114 : const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
2179 :
2180 : // if fontmap is unknown assume it doesn't have the glyphs
2181 11114 : if( !bRet )
2182 0 : return nIndex;
2183 :
2184 51382 : for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex )
2185 48598 : if( ! pFontCharMap->HasChar( rStr[i] ) )
2186 8330 : return nIndex;
2187 :
2188 2784 : pFontCharMap = 0;
2189 :
2190 13898 : return -1;
2191 1233 : }
2192 :
2193 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|