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