LibreOffice Module vcl (master)  1
outdev/font.cxx
Go to the documentation of this file.
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 #include <i18nlangtag/lang.h>
22 
23 #include <unotools/configmgr.hxx>
24 #include <vcl/metric.hxx>
25 #include <vcl/virdev.hxx>
26 #include <vcl/print.hxx>
27 #include <vcl/sysdata.hxx>
28 #include <vcl/fontcharmap.hxx>
29 #include <vcl/event.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <sal/log.hxx>
33 #include <tools/debug.hxx>
34 
35 #include <sallayout.hxx>
36 #include <salgdi.hxx>
37 #include <svdata.hxx>
38 #include <impglyphitem.hxx>
39 
40 #include <outdev.h>
41 #include <window.h>
42 
44 
45 #include <strings.hrc>
46 
47 FontMetric OutputDevice::GetDevFont( int nDevFontIndex ) const
48 {
49  FontMetric aFontMetric;
50 
52 
53  int nCount = GetDevFontCount();
54  if( nDevFontIndex < nCount )
55  {
56  const PhysicalFontFace& rData = *mpDeviceFontList->Get( nDevFontIndex );
57  aFontMetric.SetFamilyName( rData.GetFamilyName() );
58  aFontMetric.SetStyleName( rData.GetStyleName() );
59  aFontMetric.SetCharSet( rData.GetCharSet() );
60  aFontMetric.SetFamily( rData.GetFamilyType() );
61  aFontMetric.SetPitch( rData.GetPitch() );
62  aFontMetric.SetWeight( rData.GetWeight() );
63  aFontMetric.SetItalic( rData.GetItalic() );
64  aFontMetric.SetAlignment( TextAlign::ALIGN_TOP );
65  aFontMetric.SetWidthType( rData.GetWidthType() );
66  aFontMetric.SetQuality( rData.GetQuality() );
67  }
68 
69  return aFontMetric;
70 }
71 
73 {
74  if( !mpDeviceFontList )
75  {
76  if (!mxFontCollection)
77  {
78  return 0;
79  }
80 
81  mpDeviceFontList = mxFontCollection->GetDeviceFontList();
82 
83  if (!mpDeviceFontList->Count())
84  {
85  mpDeviceFontList.reset();
86  return 0;
87  }
88  }
89  return mpDeviceFontList->Count();
90 }
91 
92 bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const
93 {
95  PhysicalFontFamily* pFound = mxFontCollection->FindFontFamily( rFontName );
96  return (pFound != nullptr);
97 }
98 
100 {
101  mpDeviceFontSizeList.reset();
102 
104  mpDeviceFontSizeList = mxFontCollection->GetDeviceFontSizeList( rFont.GetFamilyName() );
105  return mpDeviceFontSizeList->Count();
106 }
107 
108 Size OutputDevice::GetDevFontSize( const vcl::Font& rFont, int nSizeIndex ) const
109 {
110  // check range
111  int nCount = GetDevFontSizeCount( rFont );
112  if ( nSizeIndex >= nCount )
113  return Size();
114 
115  // when mapping is enabled round to .5 points
116  Size aSize( 0, mpDeviceFontSizeList->Get( nSizeIndex ) );
117  if ( mbMap )
118  {
119  aSize.setHeight( aSize.Height() * 10 );
120  MapMode aMap( MapUnit::Map10thInch, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
121  aSize = PixelToLogic( aSize, aMap );
122  aSize.AdjustHeight(5 );
123  aSize.setHeight( aSize.Height() / 10 );
124  long nRound = aSize.Height() % 5;
125  if ( nRound >= 3 )
126  aSize.AdjustHeight(5-nRound);
127  else
128  aSize.AdjustHeight( -nRound );
129  aSize.setHeight( aSize.Height() * 10 );
130  aSize = LogicToPixel( aSize, aMap );
131  aSize = PixelToLogic( aSize );
132  aSize.AdjustHeight(5 );
133  aSize.setHeight( aSize.Height() / 10 );
134  }
135  return aSize;
136 }
137 
138 namespace
139 {
140  struct UpdateFontsGuard
141  {
142  UpdateFontsGuard()
143  {
145  }
146 
147  ~UpdateFontsGuard()
148  {
150  }
151  };
152 }
153 
154 bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName )
155 {
156  UpdateFontsGuard aUpdateFontsGuard;
157 
159 
160  if( !mpGraphics && !AcquireGraphics() )
161  return false;
162 
163  bool bRC = mpGraphics->AddTempDevFont( mxFontCollection.get(), rFileURL, rFontName );
164  if( !bRC )
165  return false;
166 
167  if( mpAlphaVDev )
168  mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
169 
170  return true;
171 }
172 
173 bool OutputDevice::GetFontFeatures(std::vector<vcl::font::Feature>& rFontFeatures) const
174 {
175  if (!ImplNewFont())
176  return false;
177 
178  LogicalFontInstance* pFontInstance = mpFontInstance.get();
179  if (!pFontInstance)
180  return false;
181 
182  hb_font_t* pHbFont = pFontInstance->GetHbFont();
183  if (!pHbFont)
184  return false;
185 
186  hb_face_t* pHbFace = hb_font_get_face(pHbFont);
187  if (!pHbFace)
188  return false;
189 
191 
192  vcl::font::FeatureCollector aFeatureCollector(pHbFace, rFontFeatures, eOfficeLanguage);
193  aFeatureCollector.collect();
194 
195  return true;
196 }
197 
199 {
200  FontMetric aMetric;
201  if (!ImplNewFont())
202  return aMetric;
203 
204  LogicalFontInstance* pFontInstance = mpFontInstance.get();
205  ImplFontMetricDataRef xFontMetric = pFontInstance->mxFontMetric;
206 
207  // prepare metric
208  aMetric = maFont;
209 
210  // set aMetric with info from font
211  aMetric.SetFamilyName( maFont.GetFamilyName() );
212  aMetric.SetStyleName( xFontMetric->GetStyleName() );
213  aMetric.SetFontSize( PixelToLogic( Size( xFontMetric->GetWidth(), xFontMetric->GetAscent() + xFontMetric->GetDescent() - xFontMetric->GetInternalLeading() ) ) );
214  aMetric.SetCharSet( xFontMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
215  aMetric.SetFamily( xFontMetric->GetFamilyType() );
216  aMetric.SetPitch( xFontMetric->GetPitch() );
217  aMetric.SetWeight( xFontMetric->GetWeight() );
218  aMetric.SetItalic( xFontMetric->GetItalic() );
219  aMetric.SetAlignment( TextAlign::ALIGN_TOP );
220  aMetric.SetWidthType( xFontMetric->GetWidthType() );
221  if ( pFontInstance->mnOwnOrientation )
222  aMetric.SetOrientation( pFontInstance->mnOwnOrientation );
223  else
224  aMetric.SetOrientation( xFontMetric->GetOrientation() );
225 
226  // set remaining metric fields
227  aMetric.SetFullstopCenteredFlag( xFontMetric->IsFullstopCentered() );
228  aMetric.SetBulletOffset( xFontMetric->GetBulletOffset() );
229  aMetric.SetAscent( ImplDevicePixelToLogicHeight( xFontMetric->GetAscent() + mnEmphasisAscent ) );
232  // OutputDevice has its own external leading function due to #i60945#
234  aMetric.SetLineHeight( ImplDevicePixelToLogicHeight( xFontMetric->GetAscent() + xFontMetric->GetDescent() + mnEmphasisAscent + mnEmphasisDescent ) );
235  aMetric.SetSlant( ImplDevicePixelToLogicHeight( xFontMetric->GetSlant() ) );
236 
237  // get miscellaneous data
238  aMetric.SetQuality( xFontMetric->GetQuality() );
239 
240  SAL_INFO("vcl.gdi.fontmetric", "OutputDevice::GetFontMetric:" << aMetric);
241 
242  xFontMetric = nullptr;
243 
244  return aMetric;
245 }
246 
248 {
249  // select font, query metrics, select original font again
250  vcl::Font aOldFont = GetFont();
251  const_cast<OutputDevice*>(this)->SetFont( rFont );
252  FontMetric aMetric( GetFontMetric() );
253  const_cast<OutputDevice*>(this)->SetFont( aOldFont );
254  return aMetric;
255 }
256 
257 bool OutputDevice::GetFontCharMap( FontCharMapRef& rxFontCharMap ) const
258 {
259  if (!InitFont())
260  return false;
261 
262  FontCharMapRef xFontCharMap ( mpGraphics->GetFontCharMap() );
263  if (!xFontCharMap.is())
264  {
265  FontCharMapRef xDefaultMap( new FontCharMap() );
266  rxFontCharMap = xDefaultMap;
267  }
268  else
269  rxFontCharMap = xFontCharMap;
270 
271  return !rxFontCharMap->IsDefaultMap();
272 }
273 
275 {
276  if (!InitFont())
277  return false;
278  return mpGraphics->GetFontCapabilities(rFontCapabilities);
279 }
280 
281 void OutputDevice::ImplGetEmphasisMark( tools::PolyPolygon& rPolyPoly, bool& rPolyLine,
282  tools::Rectangle& rRect1, tools::Rectangle& rRect2,
283  long& rYOff, long& rWidth,
284  FontEmphasisMark eEmphasis,
285  long nHeight )
286 {
287  static const PolyFlags aAccentPolyFlags[24] =
288  {
289  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control,
290  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control,
291  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control,
292  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control,
293  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control,
294  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control,
295  PolyFlags::Normal, PolyFlags::Normal, PolyFlags::Control,
296  PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control
297  };
298 
299  static const long aAccentPos[48] =
300  {
301  78, 0,
302  348, 79,
303  599, 235,
304  843, 469,
305  938, 574,
306  990, 669,
307  990, 773,
308  990, 843,
309  964, 895,
310  921, 947,
311  886, 982,
312  860, 999,
313  825, 999,
314  764, 999,
315  721, 964,
316  686, 895,
317  625, 791,
318  556, 660,
319  469, 504,
320  400, 400,
321  261, 252,
322  61, 61,
323  0, 27,
324  9, 0
325  };
326 
327  rWidth = 0;
328  rYOff = 0;
329  rPolyLine = false;
330 
331  if ( !nHeight )
332  return;
333 
334  FontEmphasisMark nEmphasisStyle = eEmphasis & FontEmphasisMark::Style;
335  long nDotSize = 0;
336  switch ( nEmphasisStyle )
337  {
338  case FontEmphasisMark::Dot:
339  // Dot has 55% of the height
340  nDotSize = (nHeight*550)/1000;
341  if ( !nDotSize )
342  nDotSize = 1;
343  if ( nDotSize <= 2 )
344  rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) );
345  else
346  {
347  long nRad = nDotSize/2;
348  tools::Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
349  rPolyPoly.Insert( aPoly );
350  }
351  rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks
352  rWidth = nDotSize;
353  break;
354 
355  case FontEmphasisMark::Circle:
356  // Dot has 80% of the height
357  nDotSize = (nHeight*800)/1000;
358  if ( !nDotSize )
359  nDotSize = 1;
360  if ( nDotSize <= 2 )
361  rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) );
362  else
363  {
364  long nRad = nDotSize/2;
365  tools::Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
366  rPolyPoly.Insert( aPoly );
367  // BorderWidth is 15%
368  long nBorder = (nDotSize*150)/1000;
369  if ( nBorder <= 1 )
370  rPolyLine = true;
371  else
372  {
373  tools::Polygon aPoly2( Point( nRad, nRad ),
374  nRad-nBorder, nRad-nBorder );
375  rPolyPoly.Insert( aPoly2 );
376  }
377  }
378  rWidth = nDotSize;
379  break;
380 
381  case FontEmphasisMark::Disc:
382  // Dot has 80% of the height
383  nDotSize = (nHeight*800)/1000;
384  if ( !nDotSize )
385  nDotSize = 1;
386  if ( nDotSize <= 2 )
387  rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) );
388  else
389  {
390  long nRad = nDotSize/2;
391  tools::Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
392  rPolyPoly.Insert( aPoly );
393  }
394  rWidth = nDotSize;
395  break;
396 
397  case FontEmphasisMark::Accent:
398  // Dot has 80% of the height
399  nDotSize = (nHeight*800)/1000;
400  if ( !nDotSize )
401  nDotSize = 1;
402  if ( nDotSize <= 2 )
403  {
404  if ( nDotSize == 1 )
405  {
406  rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) );
407  rWidth = nDotSize;
408  }
409  else
410  {
411  rRect1 = tools::Rectangle( Point(), Size( 1, 1 ) );
412  rRect2 = tools::Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
413  }
414  }
415  else
416  {
417  tools::Polygon aPoly( SAL_N_ELEMENTS( aAccentPos ) / 2,
418  reinterpret_cast<const Point*>(aAccentPos),
419  aAccentPolyFlags );
420  double dScale = static_cast<double>(nDotSize)/1000.0;
421  aPoly.Scale( dScale, dScale );
422  tools::Polygon aTemp;
423  aPoly.AdaptiveSubdivide( aTemp );
424  tools::Rectangle aBoundRect = aTemp.GetBoundRect();
425  rWidth = aBoundRect.GetWidth();
426  nDotSize = aBoundRect.GetHeight();
427  rPolyPoly.Insert( aTemp );
428  }
429  break;
430  default: break;
431  }
432 
433  // calculate position
434  long nOffY = 1+(mnDPIY/300); // one visible pixel space
435  long nSpaceY = nHeight-nDotSize;
436  if ( nSpaceY >= nOffY*2 )
437  rYOff += nOffY;
438  if ( !(eEmphasis & FontEmphasisMark::PosBelow) )
439  rYOff += nDotSize;
440 }
441 
443 {
444  FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
445 
446  // If no Position is set, then calculate the default position, which
447  // depends on the language
448  if ( !(nEmphasisMark & (FontEmphasisMark::PosAbove | FontEmphasisMark::PosBelow)) )
449  {
450  LanguageType eLang = rFont.GetLanguage();
451  // In Chinese Simplified the EmphasisMarks are below/left
453  nEmphasisMark |= FontEmphasisMark::PosBelow;
454  else
455  {
456  eLang = rFont.GetCJKContextLanguage();
457  // In Chinese Simplified the EmphasisMarks are below/left
459  nEmphasisMark |= FontEmphasisMark::PosBelow;
460  else
461  nEmphasisMark |= FontEmphasisMark::PosAbove;
462  }
463  }
464 
465  return nEmphasisMark;
466 }
467 
469 {
470  return mpFontInstance->mxFontMetric->GetExternalLeading();
471 }
472 
473 void OutputDevice::ImplClearFontData( const bool bNewFontLists )
474 {
475  // the currently selected logical font is no longer needed
476  mpFontInstance.clear();
477 
478  mbInitFont = true;
479  mbNewFont = true;
480 
481  if ( bNewFontLists )
482  {
483  mpDeviceFontList.reset();
484  mpDeviceFontSizeList.reset();
485 
486  // release all physically selected fonts on this device
487  if( AcquireGraphics() )
489  }
490 
491  ImplSVData* pSVData = ImplGetSVData();
492 
494  mxFontCache->Invalidate();
495 
496  if (bNewFontLists && AcquireGraphics())
497  {
499  mxFontCollection->Clear();
500  }
501 }
502 
503 void OutputDevice::RefreshFontData( const bool bNewFontLists )
504 {
505  ImplRefreshFontData( bNewFontLists );
506 }
507 
508 void OutputDevice::ImplRefreshFontData( const bool bNewFontLists )
509 {
510  if (bNewFontLists && AcquireGraphics())
512 }
513 
515 {
516  ImplClearFontData( true/*bNewFontLists*/ );
517  ImplRefreshFontData( true/*bNewFontLists*/ );
518 }
519 
520 void OutputDevice::ImplClearAllFontData(bool bNewFontLists)
521 {
522  ImplSVData* pSVData = ImplGetSVData();
523 
525 
526  // clear global font lists to have them updated
527  pSVData->maGDIData.mxScreenFontCache->Invalidate();
528  if ( !bNewFontLists )
529  return;
530 
531  pSVData->maGDIData.mxScreenFontList->Clear();
532  vcl::Window * pFrame = pSVData->maFrameData.mpFirstFrame;
533  if ( pFrame )
534  {
535  if ( pFrame->AcquireGraphics() )
536  {
537  OutputDevice *pDevice = pFrame;
538  pDevice->mpGraphics->ClearDevFontCache();
539  pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mxFontCollection.get());
540  }
541  }
542 }
543 
544 void OutputDevice::ImplRefreshAllFontData(bool bNewFontLists)
545 {
546  auto svdata = ImplGetSVData();
548  if (!svdata->mnFontUpdatesLockCount)
550  else
551  {
552  svdata->mbFontUpdatesPending = true;
553  if (bNewFontLists)
554  svdata->mbFontUpdatesNewLists = true;
555  }
556 }
557 
558 void OutputDevice::ImplUpdateAllFontData(bool bNewFontLists)
559 {
560  OutputDevice::ImplClearAllFontData(bNewFontLists);
562 }
563 
564 void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists )
565 {
566  ImplSVData* const pSVData = ImplGetSVData();
567 
568  // update all windows
569  vcl::Window* pFrame = pSVData->maFrameData.mpFirstFrame;
570  while ( pFrame )
571  {
572  ( pFrame->*pHdl )( bNewFontLists );
573 
574  vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
575  while ( pSysWin )
576  {
577  ( pSysWin->*pHdl )( bNewFontLists );
578  pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
579  }
580 
581  pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
582  }
583 
584  // update all virtual devices
585  VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
586  while ( pVirDev )
587  {
588  ( pVirDev->*pHdl )( bNewFontLists );
589  pVirDev = pVirDev->mpNext;
590  }
591 
592  // update all printers
593  Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
594  while ( pPrinter )
595  {
596  ( pPrinter->*pHdl )( bNewFontLists );
597  pPrinter = pPrinter->mpNext;
598  }
599 }
600 
602 {
603  auto svdata = ImplGetSVData();
605  if (bLock)
606  {
607  ++svdata->mnFontUpdatesLockCount;
608  }
609  else if (svdata->mnFontUpdatesLockCount > 0)
610  {
611  --svdata->mnFontUpdatesLockCount;
612  if (!svdata->mnFontUpdatesLockCount && svdata->mbFontUpdatesPending)
613  {
614  ImplRefreshAllFontData(svdata->mbFontUpdatesNewLists);
615 
616  svdata->mbFontUpdatesPending = false;
617  svdata->mbFontUpdatesNewLists = false;
618  }
619  }
620 }
621 
623 {
624  ImplSVData* pSVData = ImplGetSVData();
625  pSVData->maGDIData.mbFontSubChanged = false;
626 }
627 
629 {
630  ImplSVData* pSVData = ImplGetSVData();
631  if ( pSVData->maGDIData.mbFontSubChanged )
632  {
633  ImplUpdateAllFontData( false );
634 
638  pSVData->maGDIData.mbFontSubChanged = false;
639  }
640 }
641 
642 void OutputDevice::AddFontSubstitute( const OUString& rFontName,
643  const OUString& rReplaceFontName,
644  AddFontSubstituteFlags nFlags )
645 {
647  if( !rpSubst )
648  rpSubst = new ImplDirectFontSubstitution;
649  rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
651 }
652 
653 void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName,
654  const OUString& rSubstFontName, AddFontSubstituteFlags nFlags )
655 {
656  maFontSubstList.emplace_back( rFontName, rSubstFontName, nFlags );
657 }
658 
659 ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName,
660  const OUString& rSubstFontName, AddFontSubstituteFlags nSubstFlags )
661 : mnFlags( nSubstFlags )
662 {
663  maSearchName = GetEnglishSearchFontName( rFontName );
664  maSearchReplaceName = GetEnglishSearchFontName( rSubstFontName );
665 }
666 
668 {
670  if( pSubst )
671  pSubst->RemoveFontsSubstitute();
672 }
673 
675 {
676  maFontSubstList.clear();
677 }
678 
680  const OUString& rSearchName ) const
681 {
682  // TODO: get rid of O(N) searches
683  std::vector<ImplFontSubstEntry>::const_iterator it = std::find_if (
684  maFontSubstList.begin(), maFontSubstList.end(),
685  [&] (const ImplFontSubstEntry& s) { return (s.mnFlags & AddFontSubstituteFlags::ALWAYS)
686  && (s.maSearchName == rSearchName); } );
687  if (it != maFontSubstList.end())
688  {
689  rSubstName = it->maSearchReplaceName;
690  return true;
691  }
692  return false;
693 }
694 
695 void ImplFontSubstitute( OUString& rFontName )
696 {
697  // must be canonicalised
698  assert( GetEnglishSearchFontName( rFontName ) == rFontName );
699 
700  OUString aSubstFontName;
701 
702  // apply user-configurable font replacement (eg, from the list in Tools->Options)
704  if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName ) )
705  {
706  rFontName = aSubstFontName;
707  return;
708  }
709 }
710 
711 //hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl
713  GetDefaultFontFlags nFlags, const OutputDevice* pOutDev )
714 {
715  if (!pOutDev && !utl::ConfigManager::IsFuzzing()) // default is NULL
716  pOutDev = Application::GetDefaultDevice();
717 
718  OUString aSearch;
720  {
721  LanguageTag aLanguageTag(
722  ( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW ) ?
723  Application::GetSettings().GetUILanguageTag() :
724  LanguageTag( eLang ));
725 
727  OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType );
728 
729  if( !aDefault.isEmpty() )
730  aSearch = aDefault;
731  else
732  aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback
733  }
734  else
735  aSearch = "Liberation Serif";
736 
737  vcl::Font aFont;
738  aFont.SetPitch( PITCH_VARIABLE );
739 
740  switch ( nType )
741  {
742  case DefaultFontType::SANS_UNICODE:
743  case DefaultFontType::UI_SANS:
744  aFont.SetFamily( FAMILY_SWISS );
745  break;
746 
747  case DefaultFontType::SANS:
748  case DefaultFontType::LATIN_HEADING:
749  case DefaultFontType::LATIN_SPREADSHEET:
750  case DefaultFontType::LATIN_DISPLAY:
751  aFont.SetFamily( FAMILY_SWISS );
752  break;
753 
754  case DefaultFontType::SERIF:
755  case DefaultFontType::LATIN_TEXT:
756  case DefaultFontType::LATIN_PRESENTATION:
757  aFont.SetFamily( FAMILY_ROMAN );
758  break;
759 
760  case DefaultFontType::FIXED:
761  case DefaultFontType::LATIN_FIXED:
762  case DefaultFontType::UI_FIXED:
763  aFont.SetPitch( PITCH_FIXED );
764  aFont.SetFamily( FAMILY_MODERN );
765  break;
766 
767  case DefaultFontType::SYMBOL:
768  aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
769  break;
770 
771  case DefaultFontType::CJK_TEXT:
772  case DefaultFontType::CJK_PRESENTATION:
773  case DefaultFontType::CJK_SPREADSHEET:
774  case DefaultFontType::CJK_HEADING:
775  case DefaultFontType::CJK_DISPLAY:
776  aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
777  break;
778 
779  case DefaultFontType::CTL_TEXT:
780  case DefaultFontType::CTL_PRESENTATION:
781  case DefaultFontType::CTL_SPREADSHEET:
782  case DefaultFontType::CTL_HEADING:
783  case DefaultFontType::CTL_DISPLAY:
784  aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
785  break;
786  }
787 
788  if ( !aSearch.isEmpty() )
789  {
790  aFont.SetFontHeight( 12 ); // corresponds to nDefaultHeight
791  aFont.SetWeight( WEIGHT_NORMAL );
792  aFont.SetLanguage( eLang );
793 
794  if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
795  aFont.SetCharSet( osl_getThreadTextEncoding() );
796 
797  // Should we only return available fonts on the given device
798  if ( pOutDev )
799  {
800  pOutDev->ImplInitFontList();
801 
802  // Search Font in the FontList
803  OUString aName;
804  sal_Int32 nIndex = 0;
805  do
806  {
807  PhysicalFontFamily* pFontFamily = pOutDev->mxFontCollection->FindFontFamily( GetNextFontToken( aSearch, nIndex ) );
808  if( pFontFamily )
809  {
810  AddTokenFontName( aName, pFontFamily->GetFamilyName() );
811  if( nFlags & GetDefaultFontFlags::OnlyOne )
812  break;
813  }
814  }
815  while ( nIndex != -1 );
816  aFont.SetFamilyName( aName );
817  }
818 
819  // No Name, then set all names
820  if ( aFont.GetFamilyName().isEmpty() )
821  {
822  if ( nFlags & GetDefaultFontFlags::OnlyOne )
823  {
824  if( !pOutDev )
825  {
826  SAL_WARN_IF(!utl::ConfigManager::IsFuzzing(), "vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here");
827  aFont.SetFamilyName( aSearch.getToken( 0, ';' ) );
828  }
829  else
830  {
831  pOutDev->ImplInitFontList();
832 
833  aFont.SetFamilyName( aSearch );
834 
835  // convert to pixel height
836  Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetFontSize() );
837  if ( !aSize.Height() )
838  {
839  // use default pixel height only when logical height is zero
840  if ( aFont.GetFontHeight() )
841  aSize.setHeight( 1 );
842  else
843  aSize.setHeight( (12*pOutDev->mnDPIY)/72 );
844  }
845 
846  // use default width only when logical width is zero
847  if( (0 == aSize.Width()) && (0 != aFont.GetFontSize().Width()) )
848  aSize.setWidth( 1 );
849 
850  // get the name of the first available font
851  float fExactHeight = static_cast<float>(aSize.Height());
852  rtl::Reference<LogicalFontInstance> pFontInstance = pOutDev->mxFontCache->GetFontInstance( pOutDev->mxFontCollection.get(), aFont, aSize, fExactHeight );
853  if (pFontInstance)
854  {
855  assert(pFontInstance->GetFontFace());
856  aFont.SetFamilyName(pFontInstance->GetFontFace()->GetFamilyName());
857  }
858  }
859  }
860  else
861  aFont.SetFamilyName( aSearch );
862  }
863  }
864 
865 #if OSL_DEBUG_LEVEL > 2
866  const char* s = "SANS_UNKNOWN";
867  switch ( nType )
868  {
869  case DefaultFontType::SANS_UNICODE: s = "SANS_UNICODE"; break;
870  case DefaultFontType::UI_SANS: s = "UI_SANS"; break;
871 
872  case DefaultFontType::SANS: s = "SANS"; break;
873  case DefaultFontType::LATIN_HEADING: s = "LATIN_HEADING"; break;
874  case DefaultFontType::LATIN_SPREADSHEET: s = "LATIN_SPREADSHEET"; break;
875  case DefaultFontType::LATIN_DISPLAY: s = "LATIN_DISPLAY"; break;
876 
877  case DefaultFontType::SERIF: s = "SERIF"; break;
878  case DefaultFontType::LATIN_TEXT: s = "LATIN_TEXT"; break;
879  case DefaultFontType::LATIN_PRESENTATION: s = "LATIN_PRESENTATION"; break;
880 
881  case DefaultFontType::FIXED: s = "FIXED"; break;
882  case DefaultFontType::LATIN_FIXED: s = "LATIN_FIXED"; break;
883  case DefaultFontType::UI_FIXED: s = "UI_FIXED"; break;
884 
885  case DefaultFontType::SYMBOL: s = "SYMBOL"; break;
886 
887  case DefaultFontType::CJK_TEXT: s = "CJK_TEXT"; break;
888  case DefaultFontType::CJK_PRESENTATION: s = "CJK_PRESENTATION"; break;
889  case DefaultFontType::CJK_SPREADSHEET: s = "CJK_SPREADSHEET"; break;
890  case DefaultFontType::CJK_HEADING: s = "CJK_HEADING"; break;
891  case DefaultFontType::CJK_DISPLAY: s = "CJK_DISPLAY"; break;
892 
893  case DefaultFontType::CTL_TEXT: s = "CTL_TEXT"; break;
894  case DefaultFontType::CTL_PRESENTATION: s = "CTL_PRESENTATION"; break;
895  case DefaultFontType::CTL_SPREADSHEET: s = "CTL_SPREADSHEET"; break;
896  case DefaultFontType::CTL_HEADING: s = "CTL_HEADING"; break;
897  case DefaultFontType::CTL_DISPLAY: s = "CTL_DISPLAY"; break;
898  }
899  SAL_INFO("vcl.gdi",
900  "OutputDevice::GetDefaultFont() Type=" << s
901  << " lang=" << eLang
902  << " flags=" << static_cast<int>(nFlags)
903  << " family=\"" << aFont.GetFamilyName() << "\"");
904 #endif
905 
906  return aFont;
907 }
908 
910 {
911  if( mxFontCollection->Count() )
912  return;
913 
914  if( !(mpGraphics || AcquireGraphics()) )
915  return;
916 
917  SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" );
919 
920  // There is absolutely no way there should be no fonts available on the device
921  if( !mxFontCollection->Count() )
922  {
923  OUString aError( "Application error: no fonts and no vcl resource found on your system" );
924  OUString aResStr(VclResId(SV_ACCESSERROR_NO_FONTS));
925  if (!aResStr.isEmpty())
926  aError = aResStr;
927  Application::Abort(aError);
928  }
929 }
930 
932 {
934 
935  if (!ImplNewFont())
936  return false;
937  if (!mpFontInstance)
938  return false;
939  if (!mpGraphics)
940  {
941  if (!AcquireGraphics())
942  return false;
943  }
944  else if (!mbInitFont)
945  return true;
946 
947  mpGraphics->SetFont(mpFontInstance.get(), 0);
948  mbInitFont = false;
949  return true;
950 }
951 
953 {
954  if (!InitFont())
955  return nullptr;
956  return mpFontInstance.get();
957 }
958 
960 {
962 
963  // get correct font list on the PDF writer if necessary
964  if (GetOutDevType() == OUTDEV_PDF)
965  {
966  const ImplSVData* pSVData = ImplGetSVData();
968  || mxFontCache == pSVData->maGDIData.mxScreenFontCache )
969  const_cast<OutputDevice&>(*this).ImplUpdateFontData();
970  }
971 
972  if ( !mbNewFont )
973  return true;
974 
975  // we need a graphics
976  if ( !mpGraphics && !AcquireGraphics() )
977  {
978  SAL_WARN("vcl.gdi", "OutputDevice::ImplNewFont(): no Graphics, no Font");
979  return false;
980  }
981 
983 
984  // convert to pixel height
985  // TODO: replace integer based aSize completely with subpixel accurate type
986  float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetFontHeight()) );
988  if ( !aSize.Height() )
989  {
990  // use default pixel height only when logical height is zero
991  if ( maFont.GetFontSize().Height() )
992  aSize.setHeight( 1 );
993  else
994  aSize.setHeight( (12*mnDPIY)/72 );
995  fExactHeight = static_cast<float>(aSize.Height());
996  }
997 
998  // select the default width only when logical width is zero
999  if( (0 == aSize.Width()) && (0 != maFont.GetFontSize().Width()) )
1000  aSize.setWidth( 1 );
1001 
1002  // decide if antialiasing is appropriate
1003  bool bNonAntialiased(GetAntialiasing() & AntialiasingFlags::DisableText);
1005  {
1006  const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1007  bNonAntialiased |= bool(rStyleSettings.GetDisplayOptions() & DisplayOptions::AADisable);
1008  bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > maFont.GetFontSize().Height());
1009  }
1010 
1011  // get font entry
1013  mpFontInstance = mxFontCache->GetFontInstance(mxFontCollection.get(), maFont, aSize, fExactHeight, bNonAntialiased);
1014  const bool bNewFontInstance = pOldFontInstance.get() != mpFontInstance.get();
1015  pOldFontInstance.clear();
1016 
1017  LogicalFontInstance* pFontInstance = mpFontInstance.get();
1018 
1019  if (!pFontInstance)
1020  {
1021  SAL_WARN("vcl.gdi", "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font");
1022  return false;
1023  }
1024 
1025  // mark when lower layers need to get involved
1026  mbNewFont = false;
1027  if( bNewFontInstance )
1028  mbInitFont = true;
1029 
1030  // select font when it has not been initialized yet
1031  if (!pFontInstance->mbInit && InitFont())
1032  {
1033  // get metric data from device layers
1034  pFontInstance->mbInit = true;
1035 
1036  pFontInstance->mxFontMetric->SetOrientation( sal::static_int_cast<short>(mpFontInstance->GetFontSelectPattern().mnOrientation) );
1037  mpGraphics->GetFontMetric( pFontInstance->mxFontMetric, 0 );
1038 
1039  pFontInstance->mxFontMetric->ImplInitTextLineSize( this );
1040  pFontInstance->mxFontMetric->ImplInitAboveTextLineSize();
1041  pFontInstance->mxFontMetric->ImplInitFlags( this );
1042 
1043  pFontInstance->mnLineHeight = pFontInstance->mxFontMetric->GetAscent() + pFontInstance->mxFontMetric->GetDescent();
1044 
1045  SetFontOrientation( pFontInstance );
1046  }
1047 
1048  // calculate EmphasisArea
1049  mnEmphasisAscent = 0;
1050  mnEmphasisDescent = 0;
1051  if ( maFont.GetEmphasisMark() & FontEmphasisMark::Style )
1052  {
1054  long nEmphasisHeight = (pFontInstance->mnLineHeight*250)/1000;
1055  if ( nEmphasisHeight < 1 )
1056  nEmphasisHeight = 1;
1057  if ( nEmphasisMark & FontEmphasisMark::PosBelow )
1058  mnEmphasisDescent = nEmphasisHeight;
1059  else
1060  mnEmphasisAscent = nEmphasisHeight;
1061  }
1062 
1063  // calculate text offset depending on TextAlignment
1064  TextAlign eAlign = maFont.GetAlignment();
1065  if ( eAlign == ALIGN_BASELINE )
1066  {
1067  mnTextOffX = 0;
1068  mnTextOffY = 0;
1069  }
1070  else if ( eAlign == ALIGN_TOP )
1071  {
1072  mnTextOffX = 0;
1073  mnTextOffY = +pFontInstance->mxFontMetric->GetAscent() + mnEmphasisAscent;
1074  if ( pFontInstance->mnOrientation )
1075  {
1076  Point aOriginPt(0, 0);
1077  aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontInstance->mnOrientation );
1078  }
1079  }
1080  else // eAlign == ALIGN_BOTTOM
1081  {
1082  mnTextOffX = 0;
1083  mnTextOffY = -pFontInstance->mxFontMetric->GetDescent() + mnEmphasisDescent;
1084  if ( pFontInstance->mnOrientation )
1085  {
1086  Point aOriginPt(0, 0);
1087  aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontInstance->mnOrientation );
1088  }
1089  }
1090 
1096 
1097 
1098  bool bRet = true;
1099 
1100  // #95414# fix for OLE objects which use scale factors very creatively
1101  if( mbMap && !aSize.Width() )
1102  {
1103  int nOrigWidth = pFontInstance->mxFontMetric->GetWidth();
1104  float fStretch = static_cast<float>(maMapRes.mnMapScNumX) * maMapRes.mnMapScDenomY;
1105  fStretch /= static_cast<float>(maMapRes.mnMapScNumY) * maMapRes.mnMapScDenomX;
1106  int nNewWidth = static_cast<int>(nOrigWidth * fStretch + 0.5);
1107  if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
1108  {
1109  Size aOrigSize = maFont.GetFontSize();
1110  const_cast<vcl::Font&>(maFont).SetFontSize( Size( nNewWidth, aSize.Height() ) );
1111  mbMap = false;
1112  mbNewFont = true;
1113  bRet = ImplNewFont(); // recurse once using stretched width
1114  mbMap = true;
1115  const_cast<vcl::Font&>(maFont).SetFontSize( aOrigSize );
1116  }
1117  }
1118 
1119  return bRet;
1120 }
1121 
1122 void OutputDevice::SetFontOrientation( LogicalFontInstance* const pFontInstance ) const
1123 {
1124  if( pFontInstance->GetFontSelectPattern().mnOrientation && !pFontInstance->mxFontMetric->GetOrientation() )
1125  {
1126  pFontInstance->mnOwnOrientation = sal::static_int_cast<short>(pFontInstance->GetFontSelectPattern().mnOrientation);
1127  pFontInstance->mnOrientation = pFontInstance->mnOwnOrientation;
1128  }
1129  else
1130  {
1131  pFontInstance->mnOrientation = pFontInstance->mxFontMetric->GetOrientation();
1132  }
1133 }
1134 
1135 void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
1136  const tools::PolyPolygon& rPolyPoly, bool bPolyLine,
1137  const tools::Rectangle& rRect1, const tools::Rectangle& rRect2 )
1138 {
1139  if( IsRTLEnabled() )
1140  nX = nBaseX - (nX - nBaseX - 1);
1141 
1142  nX -= mnOutOffX;
1143  nY -= mnOutOffY;
1144 
1145  if ( rPolyPoly.Count() )
1146  {
1147  if ( bPolyLine )
1148  {
1149  tools::Polygon aPoly = rPolyPoly.GetObject( 0 );
1150  aPoly.Move( nX, nY );
1151  DrawPolyLine( aPoly );
1152  }
1153  else
1154  {
1155  tools::PolyPolygon aPolyPoly = rPolyPoly;
1156  aPolyPoly.Move( nX, nY );
1157  DrawPolyPolygon( aPolyPoly );
1158  }
1159  }
1160 
1161  if ( !rRect1.IsEmpty() )
1162  {
1163  tools::Rectangle aRect( Point( nX+rRect1.Left(),
1164  nY+rRect1.Top() ), rRect1.GetSize() );
1165  DrawRect( aRect );
1166  }
1167 
1168  if ( !rRect2.IsEmpty() )
1169  {
1170  tools::Rectangle aRect( Point( nX+rRect2.Left(),
1171  nY+rRect2.Top() ), rRect2.GetSize() );
1172 
1173  DrawRect( aRect );
1174  }
1175 }
1176 
1178 {
1179  Color aOldLineColor = GetLineColor();
1180  Color aOldFillColor = GetFillColor();
1181  bool bOldMap = mbMap;
1182  GDIMetaFile* pOldMetaFile = mpMetaFile;
1183  mpMetaFile = nullptr;
1184  EnableMapMode( false );
1185 
1187  tools::PolyPolygon aPolyPoly;
1188  tools::Rectangle aRect1;
1189  tools::Rectangle aRect2;
1190  long nEmphasisYOff;
1191  long nEmphasisWidth;
1192  long nEmphasisHeight;
1193  bool bPolyLine;
1194 
1195  if ( nEmphasisMark & FontEmphasisMark::PosBelow )
1196  nEmphasisHeight = mnEmphasisDescent;
1197  else
1198  nEmphasisHeight = mnEmphasisAscent;
1199 
1200  ImplGetEmphasisMark( aPolyPoly, bPolyLine,
1201  aRect1, aRect2,
1202  nEmphasisYOff, nEmphasisWidth,
1203  nEmphasisMark,
1204  nEmphasisHeight );
1205 
1206  if ( bPolyLine )
1207  {
1209  SetFillColor();
1210  }
1211  else
1212  {
1213  SetLineColor();
1215  }
1216 
1217  Point aOffset(0,0);
1218 
1219  if ( nEmphasisMark & FontEmphasisMark::PosBelow )
1220  aOffset.AdjustY(mpFontInstance->mxFontMetric->GetDescent() + nEmphasisYOff );
1221  else
1222  aOffset.AdjustY( -(mpFontInstance->mxFontMetric->GetAscent() + nEmphasisYOff) );
1223 
1224  long nEmphasisWidth2 = nEmphasisWidth / 2;
1225  long nEmphasisHeight2 = nEmphasisHeight / 2;
1226  aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
1227 
1228  Point aOutPoint;
1229  tools::Rectangle aRectangle;
1230  const GlyphItem* pGlyph;
1231  int nStart = 0;
1232  while (rSalLayout.GetNextGlyph(&pGlyph, aOutPoint, nStart))
1233  {
1234  if (!pGlyph->GetGlyphBoundRect(aRectangle))
1235  continue;
1236 
1237  if (!pGlyph->IsSpacing())
1238  {
1239  Point aAdjPoint = aOffset;
1240  aAdjPoint.AdjustX(aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2 );
1241  if ( mpFontInstance->mnOrientation )
1242  {
1243  Point aOriginPt(0, 0);
1244  aOriginPt.RotateAround( aAdjPoint, mpFontInstance->mnOrientation );
1245  }
1246  aOutPoint += aAdjPoint;
1247  aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
1248  ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
1249  aOutPoint.X(), aOutPoint.Y(),
1250  aPolyPoly, bPolyLine, aRect1, aRect2 );
1251  }
1252  }
1253 
1254  SetLineColor( aOldLineColor );
1255  SetFillColor( aOldFillColor );
1256  EnableMapMode( bOldMap );
1257  mpMetaFile = pOldMetaFile;
1258 }
1259 
1260 std::unique_ptr<SalLayout> OutputDevice::getFallbackLayout(
1261  LogicalFontInstance* pLogicalFont, int nFallbackLevel,
1262  ImplLayoutArgs& rLayoutArgs) const
1263 {
1264  // we need a graphics
1265  if (!mpGraphics && !AcquireGraphics())
1266  return nullptr;
1267 
1268  assert(mpGraphics != nullptr);
1269  mpGraphics->SetFont( pLogicalFont, nFallbackLevel );
1270 
1271  rLayoutArgs.ResetPos();
1272  std::unique_ptr<GenericSalLayout> pFallback = mpGraphics->GetTextLayout(nFallbackLevel);
1273 
1274  if (!pFallback)
1275  return nullptr;
1276 
1277  if (!pFallback->LayoutText(rLayoutArgs, nullptr))
1278  {
1279  // there is no need for a font that couldn't resolve anything
1280  return nullptr;
1281  }
1282 
1283  return pFallback;
1284 }
1285 
1286 std::unique_ptr<SalLayout> OutputDevice::ImplGlyphFallbackLayout( std::unique_ptr<SalLayout> pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
1287 {
1288  // This function relies on a valid mpFontInstance, if it doesn't exist bail out
1289  // - we'd have crashed later on anyway. At least here we can catch the error in debug
1290  // mode.
1291  if ( !mpFontInstance )
1292  {
1293  SAL_WARN ("vcl.gdi", "No font entry set in OutputDevice");
1295  return nullptr;
1296  }
1297 
1298  // prepare multi level glyph fallback
1299  std::unique_ptr<MultiSalLayout> pMultiSalLayout;
1300  ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
1301  rLayoutArgs.PrepareFallback();
1302  rLayoutArgs.mnFlags |= SalLayoutFlags::ForFallback;
1303 
1304  // get list of code units that need glyph fallback
1305  int nCharPos = -1;
1306  bool bRTL = false;
1307  OUStringBuffer aMissingCodeBuf(512);
1308  while (rLayoutArgs.GetNextPos( &nCharPos, &bRTL))
1309  aMissingCodeBuf.append(rLayoutArgs.mrStr[nCharPos]);
1310  rLayoutArgs.ResetPos();
1311  OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
1312 
1313  FontSelectPattern aFontSelData(mpFontInstance->GetFontSelectPattern());
1314 
1315  // try if fallback fonts support the missing code units
1316  for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
1317  {
1318  // find a font family suited for glyph fallback
1319  // GetGlyphFallbackFont() needs a valid FontInstance
1320  // if the system-specific glyph fallback is active
1321  rtl::Reference<LogicalFontInstance> pFallbackFont = mxFontCache->GetGlyphFallbackFont( mxFontCollection.get(),
1322  aFontSelData, mpFontInstance.get(), nFallbackLevel, aMissingCodes );
1323  if( !pFallbackFont )
1324  break;
1325 
1326  if( nFallbackLevel < MAX_FALLBACK-1)
1327  {
1328  // ignore fallback font if it is the same as the original font
1329  // unless we are looking for a substitution for 0x202F, in which
1330  // case we'll just use a normal space
1331  if( mpFontInstance->GetFontFace() == pFallbackFont->GetFontFace() &&
1332  aMissingCodes.indexOf(0x202F) == -1 )
1333  {
1334  continue;
1335  }
1336  }
1337 
1338  // create and add glyph fallback layout to multilayout
1339  std::unique_ptr<SalLayout> pFallback = getFallbackLayout(pFallbackFont.get(),
1340  nFallbackLevel, rLayoutArgs);
1341  if (pFallback)
1342  {
1343  if( !pMultiSalLayout )
1344  pMultiSalLayout.reset( new MultiSalLayout( std::move(pSalLayout) ) );
1345  pMultiSalLayout->AddFallback(std::move(pFallback), rLayoutArgs.maRuns);
1346  if (nFallbackLevel == MAX_FALLBACK-1)
1347  pMultiSalLayout->SetIncomplete(true);
1348  }
1349 
1350  // break when this fallback was sufficient
1351  if( !rLayoutArgs.PrepareFallback() )
1352  break;
1353  }
1354 
1355  if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs, nullptr ) )
1356  pSalLayout = std::move(pMultiSalLayout);
1357 
1358  // restore orig font settings
1359  pSalLayout->InitFont();
1360  rLayoutArgs.maRuns = aLayoutRuns;
1361 
1362  return pSalLayout;
1363 }
1364 
1366 {
1367  if (!ImplNewFont())
1368  return 0;
1369 
1370  return ImplDevicePixelToLogicWidth( mpFontInstance->mxFontMetric->GetMinKashida() );
1371 }
1372 
1373 sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt,
1374  sal_Int32 nIdx, sal_Int32 nLen,
1375  sal_Int32 nKashCount,
1376  const sal_Int32* pKashidaPos,
1377  sal_Int32* pKashidaPosDropped ) const
1378 {
1379  // do layout
1380  std::unique_ptr<SalLayout> pSalLayout = ImplLayout( rTxt, nIdx, nLen );
1381  if( !pSalLayout )
1382  return 0;
1383  sal_Int32 nDropped = 0;
1384  for( int i = 0; i < nKashCount; ++i )
1385  {
1386  if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
1387  {
1388  pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
1389  ++nDropped;
1390  }
1391  }
1392  return nDropped;
1393 }
1394 
1395 bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr,
1396  int nIndex, int nLen, MetricVector& rVector )
1397 {
1398  rVector.clear();
1399 
1400  if( nIndex >= rStr.getLength() )
1401  return false;
1402 
1403  if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
1404  {
1405  nLen = rStr.getLength() - nIndex;
1406  }
1407 
1408  tools::Rectangle aRect;
1409  for( int i = 0; i < nLen; i++ )
1410  {
1411  if( !GetTextBoundRect( aRect, rStr, nIndex, nIndex + i, 1 ) )
1412  break;
1413  aRect.Move( rOrigin.X(), rOrigin.Y() );
1414  rVector.push_back( aRect );
1415  }
1416 
1417  return (nLen == static_cast<int>(rVector.size()));
1418 }
1419 
1420 sal_Int32 OutputDevice::HasGlyphs( const vcl::Font& rTempFont, const OUString& rStr,
1421  sal_Int32 nIndex, sal_Int32 nLen ) const
1422 {
1423  if( nIndex >= rStr.getLength() )
1424  return nIndex;
1425  sal_Int32 nEnd;
1426  if( nLen == -1 )
1427  nEnd = rStr.getLength();
1428  else
1429  nEnd = std::min( rStr.getLength(), nIndex + nLen );
1430 
1431  SAL_WARN_IF( nIndex >= nEnd, "vcl.gdi", "StartPos >= EndPos?" );
1432  SAL_WARN_IF( nEnd > rStr.getLength(), "vcl.gdi", "String too short" );
1433 
1434  // to get the map temporarily set font
1435  const vcl::Font aOrigFont = GetFont();
1436  const_cast<OutputDevice&>(*this).SetFont( rTempFont );
1437  FontCharMapRef xFontCharMap;
1438  bool bRet = GetFontCharMap( xFontCharMap );
1439  const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
1440 
1441  // if fontmap is unknown assume it doesn't have the glyphs
1442  if( !bRet )
1443  return nIndex;
1444 
1445  for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex )
1446  if( ! xFontCharMap->HasChar( rStr[i] ) )
1447  return nIndex;
1448 
1449  return -1;
1450 }
1451 
1453 
1455 
1457 {
1459 }
1460 
1462 {
1463  mxFontCache = std::make_shared<ImplFontCache>();
1464 }
1465 
1466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetFamily(FontFamily)
Definition: font/font.cxx:123
SAL_DLLPRIVATE std::unique_ptr< SalLayout > ImplGlyphFallbackLayout(std::unique_ptr< SalLayout >, ImplLayoutArgs &) const
sal_uInt16 Count() const
long Width() const
const Color & GetTextColor() const
Definition: outdev.hxx:1125
void SetLineHeight(long nHeight)
Definition: metric.hxx:52
OutDevType GetOutDevType() const
Definition: outdev.hxx:524
long mnOutOffX
Output offset for device output in pixel (pseudo window offset within window system's frames) ...
Definition: outdev.hxx:340
bool HasChar(sal_UCS4) const
Does the font character map include the UCS4 character?
#define LANGUAGE_NONE
virtual void ClearDevFontCache()=0
long GetWidth() const
static vcl::Font GetDefaultFont(DefaultFontType nType, LanguageType eLang, GetDefaultFontFlags nFlags, const OutputDevice *pOutDev=nullptr)
bool GetFontCharMap(FontCharMapRef &rxFontCharMap) const
sal_Int32 nIndex
const tools::Polygon & GetObject(sal_uInt16 nPos) const
void SetFontSize(const Size &)
Definition: font/font.cxx:117
const OUString & GetStyleName() const
static void AddFontSubstitute(const OUString &rFontName, const OUString &rReplaceFontName, AddFontSubstituteFlags nFlags)
long GetHeight() const
const OUString & GetFamilyName() const
Definition: font/font.cxx:670
std::vector< tools::Rectangle > MetricVector
Definition: outdev.hxx:137
bool mbFontSubChanged
Definition: svdata.hxx:228
void SetBulletOffset(long nOffset)
Definition: metric.hxx:54
long GetFontHeight() const
Definition: font/font.cxx:675
static void NotifyAllWindows(DataChangedEvent &rDCEvt)
Notify all windows that the application has changed data.
Definition: svapp.cxx:733
FAMILY_MODERN
virtual void ImplRefreshFontData(bool bNewFontLists)
VclPtr< VirtualDevice > mpNext
Definition: virdev.hxx:50
bool IsDefaultMap() const
Determines if the font character map is the "default".
long mnEmphasisAscent
Definition: outdev.hxx:351
long Height() const
long mnOutOffY
Output offset for device output in pixel (pseudo window offset within window system's frames) ...
Definition: outdev.hxx:342
bool GetNextPos(int *nCharPos, bool *bRTL)
Definition: sallayout.hxx:108
bool IsOutline() const
Definition: font/font.cxx:707
LanguageType getLanguageType(bool bResolveSystem=true) const
sal_Int32 HasGlyphs(const vcl::Font &rFont, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1) const
bool mbTextSpecial
Definition: outdev.hxx:390
FontLineStyle GetOverline() const
Definition: font/font.cxx:711
static SAL_DLLPRIVATE void ImplUpdateFontDataForAllFrames(FontUpdateHandler_t pHdl, bool bNewFontLists)
void SetInternalLeading(long nIntLeading)
Definition: metric.hxx:51
LanguageType GetCJKContextLanguage() const
Definition: font/font.cxx:684
#define MAX_FALLBACK
Definition: sallayout.hxx:41
bool FindFontSubstitute(OUString &rSubstName, const OUString &rFontName) const
static void EndFontSubstitution()
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:706
virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const =0
FontEmphasisMark
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
OUString maSearchReplaceName
Definition: outdev.h:88
SAL_DLLPRIVATE std::unique_ptr< SalLayout > getFallbackLayout(LogicalFontInstance *pLogicalFont, int nFallbackLevel, ImplLayoutArgs &rLayoutArgs) const
void SetDescent(long nDescent)
Definition: metric.hxx:49
void SetWeight(FontWeight)
Definition: font/font.cxx:215
void DrawPolyLine(const tools::Polygon &rPoly)
Render the given polygon as a line stroke.
Definition: polyline.cxx:33
const ContentProperties & rData
std::shared_ptr< PhysicalFontCollection > mxFontCollection
Definition: outdev.hxx:320
sal_Int32 mnDPIY
Definition: outdev.hxx:346
hb_font_t * GetHbFont()
std::unique_ptr< ImplDeviceFontSizeList > mpDeviceFontSizeList
Definition: outdev.hxx:322
static void LockFontUpdates(bool bLock)
void SetCharSet(rtl_TextEncoding)
Definition: font/font.cxx:129
void ReleaseFontCollection()
void ImplInitAboveTextLineSize()
Definition: fontmetric.cxx:216
FAMILY_ROMAN
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:646
bool IsSpacing() const
bool mbMap
Definition: outdev.hxx:374
SAL_DLLPRIVATE const LogicalFontInstance * GetFontInstance() const
ImplFontMetricDataRef mxFontMetric
void SetOrientation(short nLineOrientation)
Definition: font/font.cxx:192
AntialiasingFlags GetAntialiasing() const
Definition: outdev.hxx:604
ImplSVGDIData maGDIData
Definition: svdata.hxx:393
virtual std::unique_ptr< GenericSalLayout > GetTextLayout(int nFallbackLevel)=0
void ImplInitTextLineSize(const OutputDevice *pDev)
Definition: fontmetric.cxx:126
void Scale(double fScaleX, double fScaleY)
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, const long *pDXArray=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Return the exact bounding rectangle of rStr.
Definition: text.cxx:2265
FontAlign GetAlignment() const
Definition: font/font.cxx:668
void SetQuality(int)
Definition: font/font.cxx:703
void Move(long nHorzMoveDelta, long nVertMoveDelta)
virtual FontCharMapRef GetFontCharMap() const =0
OUString maSearchName
Definition: outdev.h:87
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1051
bool IsEmpty() const
HashMap_OWString_Interface aMap
SAL_DLLPRIVATE void ImplInitFontList() const
FuncFlags mnFlags
LanguageType GetLanguage() const
Definition: font/font.cxx:683
VclPtr< Printer > mpNext
Definition: print.hxx:152
void SetExternalLeading(long nExtLeading)
Definition: metric.hxx:50
static void ImplCallEventListenersApplicationDataChanged(void *pData)
Send event to all VCL application event listeners.
Definition: svapp.cxx:752
AddFontSubstituteFlags
Definition: outdev.hxx:242
LINESTYLE_NONE
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
OUString GetEnglishSearchFontName(const OUString &rInName)
const vcl::Font & GetFont() const
Definition: outdev.hxx:649
ImplLayoutRuns maRuns
Definition: sallayout.hxx:94
static bool IsFuzzing()
int nCount
void RefreshFontData(const bool bNewFontLists)
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
FontMetric GetFontMetric() const
VclPtr< VirtualDevice > mpFirstVirDev
Definition: svdata.hxx:217
long Top() const
PITCH_VARIABLE
SAL_DLLPRIVATE bool ImplNewFont() const
void SetFontCollectionFromSVData()
FontItalic GetItalic() const
bool GetFontFeatures(std::vector< vcl::font::Feature > &rFontFeatures) const
rtl_TextEncoding GetCharSet() const
void ReleaseFontCache()
static void BeginFontSubstitution()
void AddTokenFontName(OUString &rName, const OUString &rNewToken)
GetDefaultFontFlags
Definition: outdev.hxx:254
FontEmphasisMark GetEmphasisMark() const
Definition: font/font.cxx:713
void SetLanguage(LanguageType)
Definition: font/font.cxx:174
bool AddTempDevFont(const OUString &rFileURL, const OUString &rFontName)
OUString getDefaultFont(const LanguageTag &rLanguageTag, DefaultFontType nType) const
void DrawRect(const tools::Rectangle &rRect)
Definition: rect.cxx:51
void SetPitch(FontPitch ePitch)
Definition: font/font.cxx:186
const LanguageTag & GetLanguageTag() const
void Move(long nHorzMove, long nVertMove)
#define SAL_N_ELEMENTS(arr)
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:314
abstract base class for physical font faces
const OUString & mrStr
Definition: sallayout.hxx:81
FontFamily GetFamilyType() const
FontMetric GetDevFont(int nDevFontIndex) const
Definition: outdev/font.cxx:47
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
VclPtr< Printer > mpFirstPrinter
Definition: svdata.hxx:219
void Move(long nHorzMove, long nVertMove)
void SetAlignment(FontAlign)
Definition: font/font.cxx:101
ImplFontSubstEntry(const OUString &rFontName, const OUString &rSubstFontName, AddFontSubstituteFlags nSubstFlags)
static SAL_DLLPRIVATE void ImplRefreshAllFontData(bool bNewFontLists)
void SetLineColor()
void SetOrientation(short nOrientation)
ALIGN_BASELINE
virtual long GetFontExtLeading() const
bool IsRTLEnabled() const
Definition: outdev.hxx:1356
void SetFamilyName(const OUString &rFamilyName)
Definition: font/font.cxx:107
int i
SAL_DLLPRIVATE float ImplFloatLogicHeightToDevicePixel(float fLogicHeight) const
Convert logical height to device pixels, with exact sub-pixel value.
Definition: map.cxx:450
long GetDescent() const
bool PrepareFallback()
Definition: sallayout.cxx:489
FontWeight GetWeight() const
PITCH_FIXED
#define LANGUAGE_SYSTEM
void ImplInitFlags(const OutputDevice *pDev)
Definition: fontmetric.cxx:266
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
DisplayOptions GetDisplayOptions() const
std::unique_ptr< ImplDeviceFontList > mpDeviceFontList
Definition: outdev.hxx:321
virtual void SetFontOrientation(LogicalFontInstance *const pFontInstance) const
long mnMapScNumX
Definition: outdevmap.hxx:27
void SetFillColor()
bool mbNewFont
Definition: outdev.hxx:388
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:302
WEIGHT_NORMAL
const Color & GetLineColor() const
Definition: outdev.hxx:630
bool mbTextLines
Definition: outdev.hxx:389
bool IsFontAvailable(const OUString &rFontName) const
Definition: outdev/font.cxx:92
std::unique_ptr< WindowImpl > mpWindowImpl
Definition: window.hxx:519
static SAL_DLLPRIVATE FontEmphasisMark ImplGetEmphasisMarkStyle(const vcl::Font &rFont)
long const nBorder
bool IsShadow() const
Definition: font/font.cxx:708
#define LANGUAGE_DONTKNOW
const Size & GetFontSize() const
Definition: font/font.cxx:673
vcl::Font maFont
Definition: outdev.hxx:362
FontStrikeout GetStrikeout() const
Definition: font/font.cxx:712
int GetQuality() const
void SetWidthType(FontWidth)
Definition: font/font.cxx:221
const AllSettings & GetSettings() const
Definition: outdev.hxx:418
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), long nLogicWidth=0, const long *pLogicDXArray=nullptr, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1253
LINESTYLE_DONTKNOW
void ReleaseFonts()
Definition: salgdi.hxx:133
Size GetSize() const
static bool isSimplifiedChinese(LanguageType nLang)
Point & DrawBase()
Definition: vcllayout.hxx:69
TextAlign
bool GetGlyphBoundRects(const Point &rOrigin, const OUString &rStr, int nIndex, int nLen, MetricVector &rVector)
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1186
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:941
FAMILY_SYSTEM
static DefaultFontConfiguration & get()
FontRelief GetRelief() const
Definition: font/font.cxx:709
SAL_DLLPRIVATE void ImplDrawEmphasisMark(long nBaseX, long nX, long nY, const tools::PolyPolygon &rPolyPoly, bool bPolyLine, const tools::Rectangle &rRect1, const tools::Rectangle &rRect2)
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:329
ALIGN_TOP
const FontSelectPattern & GetFontSelectPattern() const
void SetStyleName(const OUString &rStyleName)
Definition: font/font.cxx:112
long mnMapScDenomY
Definition: outdevmap.hxx:30
void SetAscent(long nAscent)
Definition: metric.hxx:48
static void Abort(const OUString &rErrorText)
Ends the program prematurely with an error message.
Definition: svapp.cxx:254
ImplMapRes maMapRes
Definition: outdev.hxx:355
bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
#define SAL_WARN_IF(condition, area, stream)
void ResetNewFontCache()
bool IsFullstopCentered() const
void SetFont(const vcl::Font &rNewFont)
ImplSVFrameData maFrameData
Definition: svdata.hxx:394
#define SAL_INFO(area, stream)
SAL_DLLPRIVATE void ImplDrawEmphasisMarks(SalLayout &)
OUString aName
FAMILY_SWISS
void ImplFontSubstitute(OUString &rFontName)
SAL_DLLPRIVATE void ImplUpdateFontData()
SAL_DLLPRIVATE long ImplDevicePixelToLogicHeight(long nHeight) const
Convert device pixels to a height in logical units.
Definition: map.cxx:468
OUString getUserInterfaceFont(const LanguageTag &rLanguageTag) const
std::shared_ptr< ImplFontCache > mxScreenFontCache
Definition: svdata.hxx:222
short GetOrientation() const
ImplDirectFontSubstitution * mpDirectFontSubst
Definition: svdata.hxx:224
void SetFontHeight(long nHeight)
Definition: font/font.cxx:674
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
Render the given poly-polygon.
Definition: polygon.cxx:36
int GetDevFontSizeCount(const vcl::Font &) const
Definition: outdev/font.cxx:99
SAL_DLLPRIVATE void ImplGetEmphasisMark(tools::PolyPolygon &rPolyPoly, bool &rPolyLine, tools::Rectangle &rRect1, tools::Rectangle &rRect2, long &rYOff, long &rWidth, FontEmphasisMark eEmphasis, long nHeight)
virtual void ImplClearFontData(bool bNewFontLists)
bool mbInitFont
Definition: outdev.hxx:384
static SAL_DLLPRIVATE void ImplUpdateAllFontData(bool bNewFontLists)
long mnMapScDenomX
Definition: outdevmap.hxx:29
long Left() const
rtl::Reference< LogicalFontInstance > mpFontInstance
Definition: outdev.hxx:318
SalLayoutFlags mnFlags
Definition: sallayout.hxx:80
Size GetDevFontSize(const vcl::Font &rFont, int nSizeIndex) const
DefaultFontType
sal_Int32 ValidateKashidas(const OUString &rTxt, sal_Int32 nIdx, sal_Int32 nLen, sal_Int32 nKashCount, const sal_Int32 *pKashidaPos, sal_Int32 *pKashidaPosDropped) const
long mnTextOffX
font specific text alignment offsets in pixel units
Definition: outdev.hxx:349
std::vector< ImplFontSubstEntry > maFontSubstList
Definition: outdev.h:98
long GetBulletOffset() const
int GetDevFontCount() const
Definition: outdev/font.cxx:72
void SetItalic(FontItalic)
Definition: font/font.cxx:227
long mnEmphasisDescent
Definition: outdev.hxx:352
void AdaptiveSubdivide(tools::Polygon &rResult, const double d=1.0) const
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:504
STRIKEOUT_DONTKNOW
FontLineStyle GetUnderline() const
Definition: font/font.cxx:710
virtual bool GetNextGlyph(const GlyphItem **pGlyph, Point &rPos, int &nStart, const PhysicalFontFace **pFallbackFont=nullptr) const =0
SAL_DLLPRIVATE long ImplDevicePixelToLogicWidth(long nWidth) const
Convert device pixels to a width in logical units.
Definition: map.cxx:458
OUString GetNextFontToken(const OUString &rTokenStr, sal_Int32 &rIndex)
virtual void GetFontMetric(ImplFontMetricDataRef &, int nFallbackLevel)=0
std::shared_ptr< ImplFontCache > mxFontCache
Definition: outdev.hxx:319
VclPtr< vcl::Window > mpFirstFrame
Definition: svdata.hxx:237
FontWidth GetWidthType() const
long GetMinKashida() const
#define SAL_WARN(area, stream)
bool IsSymbolFont() const
OUString VclResId(const char *pId)
Definition: svdata.cxx:267
virtual bool AddTempDevFont(PhysicalFontCollection *, const OUString &rFileURL, const OUString &rFontName)=0
static void RemoveFontsSubstitute()
#define DBG_TESTSOLARMUTEX()
tools::Rectangle GetBoundRect() const
void SetFullstopCenteredFlag(bool bCentered)
Definition: metric.hxx:58
FontPitch GetPitch() const
virtual bool AcquireGraphics() const override
Acquire a graphics device that the output device uses to draw on.
Definition: window.cxx:818
virtual void SetFont(LogicalFontInstance *, int nFallbackLevel)=0
STRIKEOUT_NONE
long mnMapScNumY
Definition: outdevmap.hxx:28
void SetSlant(long nSlant)
Definition: metric.hxx:53
bool GetGlyphBoundRect(tools::Rectangle &) const
static SAL_DLLPRIVATE void ImplClearAllFontData(bool bNewFontLists)
const OUString & GetFamilyName() const
void setWidth(long nWidth)
std::shared_ptr< PhysicalFontCollection > mxScreenFontList
Definition: svdata.hxx:221
void AddFontSubstitute(const OUString &rFontName, const OUString &rSubstName, AddFontSubstituteFlags nFlags)
sal_uLong GetAntialiasingMinPixelHeight() const
long mnTextOffY
Definition: outdev.hxx:350
rtl_TextEncoding GetCharSet() const
Definition: font/font.cxx:679
const Color & GetFillColor() const
Definition: outdev.hxx:635
long GetInternalLeading() const
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:317
PolyFlags
virtual void GetDevFontList(PhysicalFontCollection *)=0
SAL_DLLPRIVATE bool InitFont() const
void setHeight(long nHeight)
const OUString & GetFamilyName() const