LibreOffice Module vcl (master)  1
PhysicalFontFamily.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 <sal/config.h>
21 
22 #include <rtl/ustring.hxx>
23 #include <unotools/fontdefs.hxx>
24 
27 
28 namespace vcl::font
29 {
30 
32  FontFamily eFamily, const utl::FontNameAttr* pFontAttr )
33 {
34  if ( eFamily != FAMILY_DONTKNOW )
35  {
36  if ( eFamily == FAMILY_SWISS )
37  rType |= ImplFontAttrs::SansSerif;
38  else if ( eFamily == FAMILY_ROMAN )
39  rType |= ImplFontAttrs::Serif;
40  else if ( eFamily == FAMILY_SCRIPT )
41  rType |= ImplFontAttrs::Script;
42  else if ( eFamily == FAMILY_MODERN )
43  rType |= ImplFontAttrs::Fixed;
44  else if ( eFamily == FAMILY_DECORATIVE )
45  rType |= ImplFontAttrs::Decorative;
46  }
47 
48  if ( pFontAttr )
49  {
50  rType |= pFontAttr->Type;
51 
52  if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
53  (pFontAttr->Weight != WEIGHT_DONTKNOW) )
54  rWeight = pFontAttr->Weight;
55  if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
56  (pFontAttr->Width != WIDTH_DONTKNOW) )
57  rWidth = pFontAttr->Width;
58  }
59 }
60 
61 static ImplFontAttrs lcl_IsCJKFont( const OUString& rFontName )
62 {
63  // Test, if Fontname includes CJK characters --> In this case we
64  // mention that it is a CJK font
65  for(int i = 0; i < rFontName.getLength(); i++)
66  {
67  const sal_Unicode ch = rFontName[i];
68  // japanese
69  if ( ((ch >= 0x3040) && (ch <= 0x30FF)) ||
70  ((ch >= 0x3190) && (ch <= 0x319F)) )
71  return ImplFontAttrs::CJK|ImplFontAttrs::CJK_JP;
72 
73  // korean
74  if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) ||
75  ((ch >= 0xA960) && (ch <= 0xA97F)) ||
76  ((ch >= 0xD7B0) && (ch <= 0xD7FF)) ||
77  ((ch >= 0x3130) && (ch <= 0x318F)) ||
78  ((ch >= 0x1100) && (ch <= 0x11FF)) )
79  return ImplFontAttrs::CJK|ImplFontAttrs::CJK_KR;
80 
81  // chinese
82  if ( (ch >= 0x3400) && (ch <= 0x9FFF) )
83  return ImplFontAttrs::CJK|ImplFontAttrs::CJK_TC|ImplFontAttrs::CJK_SC;
84 
85  // cjk
86  if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) ||
87  ((ch >= 0xFF00) && (ch <= 0xFFEE)) )
88  return ImplFontAttrs::CJK;
89 
90  }
91 
92  return ImplFontAttrs::None;
93 }
94 
95 PhysicalFontFamily::PhysicalFontFamily( const OUString& rSearchName )
96 : maSearchName( rSearchName ),
97  mnTypeFaces( FontTypeFaces::NONE ),
98  meFamily( FAMILY_DONTKNOW ),
99  mePitch( PITCH_DONTKNOW ),
100  mnMinQuality( -1 ),
101  mnMatchType( ImplFontAttrs::None ),
102  meMatchWeight( WEIGHT_DONTKNOW ),
103  meMatchWidth( WIDTH_DONTKNOW )
104 {}
105 
107 {
108 }
109 
111 {
112  if( maFontFaces.empty() )
113  {
114  maFamilyName = pNewFontFace->GetFamilyName();
115  maMapNames = pNewFontFace->GetMapNames();
116  meFamily = pNewFontFace->GetFamilyType();
117  mePitch = pNewFontFace->GetPitch();
118  mnMinQuality = pNewFontFace->GetQuality();
119  }
120  else
121  {
122  if( meFamily == FAMILY_DONTKNOW )
123  meFamily = pNewFontFace->GetFamilyType();
124  if( mePitch == PITCH_DONTKNOW )
125  mePitch = pNewFontFace->GetPitch();
126  if( mnMinQuality > pNewFontFace->GetQuality() )
127  mnMinQuality = pNewFontFace->GetQuality();
128  }
129 
130  // set attributes for attribute based font matching
132 
133  if( pNewFontFace->IsSymbolFont() )
135  else
137 
138  if( pNewFontFace->GetWeight() != WEIGHT_DONTKNOW )
139  {
140  if( pNewFontFace->GetWeight() >= WEIGHT_SEMIBOLD )
142  else if( pNewFontFace->GetWeight() <= WEIGHT_SEMILIGHT )
144  else
146  }
147 
148  if( pNewFontFace->GetItalic() == ITALIC_NONE )
150  else if( (pNewFontFace->GetItalic() == ITALIC_NORMAL)
151  || (pNewFontFace->GetItalic() == ITALIC_OBLIQUE) )
153 
154  // reassign name (sharing saves memory)
155  if( pNewFontFace->GetFamilyName() == GetFamilyName() )
156  pNewFontFace->SetFamilyName( GetFamilyName() );
157 
158  // add the new physical font face, replacing existing font face if necessary
159  // TODO: get rid of linear search?
160  auto it(maFontFaces.begin());
161  for (; it != maFontFaces.end(); ++it)
162  {
163  PhysicalFontFace* pFoundFontFace = it->get();
164  sal_Int32 eComp = pNewFontFace->CompareIgnoreSize( *pFoundFontFace );
165  if( eComp > 0 )
166  continue;
167  if( eComp < 0 )
168  break;
169 
170  // ignore duplicate if its quality is worse
171  if( pNewFontFace->GetQuality() < pFoundFontFace->GetQuality() )
172  return;
173 
174  // keep the device font if its quality is good enough
175  if( pNewFontFace->GetQuality() == pFoundFontFace->GetQuality() )
176  return;
177 
178  // replace existing font face with a better one
179  *it = pNewFontFace; // insert at sort position
180  return;
181  }
182 
183  maFontFaces.emplace(it, pNewFontFace); // insert at sort position
184 }
185 
186 // get font attributes using the normalized font family name
187 void PhysicalFontFamily::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
188  const OUString& rSearchName )
189 {
190  OUString aShortName;
191  OUString aMatchFamilyName(maMatchFamilyName);
192  // get font attributes from the decorated font name
193  utl::FontSubstConfiguration::getMapName( rSearchName, aShortName, aMatchFamilyName,
195  maMatchFamilyName = aMatchFamilyName;
196  const utl::FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
197  // eventually use the stripped name
198  if( !pFontAttr )
199  if( aShortName != rSearchName )
200  pFontAttr = rFontSubst.getSubstInfo( aShortName );
203 }
204 
206 {
207  if( maFontFaces.empty() )
208  return nullptr;
209  if( maFontFaces.size() == 1)
210  return maFontFaces[0].get();
211 
212  // FontName+StyleName should map to FamilyName+StyleName
213  const OUString& rSearchName = rFSD.maTargetName;
214  OUString aTargetStyleName;
215  const OUString* pTargetStyleName = nullptr;
216  if((rSearchName.getLength() > maSearchName.getLength())
217  && rSearchName.startsWith( maSearchName ) )
218  {
219  aTargetStyleName = rSearchName.copy(maSearchName.getLength() + 1);
220  pTargetStyleName = &aTargetStyleName;
221  }
222 
223  // TODO: linear search improve!
224  PhysicalFontFace* pBestFontFace = maFontFaces[0].get();
225  FontMatchStatus aFontMatchStatus = {0, pTargetStyleName};
226  for (auto const& font : maFontFaces)
227  {
228  PhysicalFontFace* pFoundFontFace = font.get();
229  if( pFoundFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
230  pBestFontFace = pFoundFontFace;
231  }
232 
233  return pBestFontFace;
234 }
235 
236 // update device font list with unique font faces, with uniqueness
237 // meaning different font attributes, but not different fonts sizes
239 {
240  PhysicalFontFace* pPrevFace = nullptr;
241  for (auto const& font : maFontFaces)
242  {
243  PhysicalFontFace* pFoundFontFace = font.get();
244  if( !pPrevFace || pFoundFontFace->CompareIgnoreSize( *pPrevFace ) )
245  rDevFontList.Add( pFoundFontFace );
246  pPrevFace = pFoundFontFace;
247  }
248 }
249 
251 {
252  OUString aFamilyName = GetEnglishSearchFontName( GetFamilyName() );
253  PhysicalFontFamily* pFamily(nullptr);
254 
255  for (auto const& font : maFontFaces)
256  {
257  PhysicalFontFace *pFoundFontFace = font.get();
258 
259  if (!pFamily)
260  { // tdf#98989 lazy create as family without faces won't work
261  pFamily = rFontCollection.FindOrCreateFontFamily(aFamilyName);
262  }
263  assert(pFamily);
264  pFamily->AddFontFace( pFoundFontFace );
265  }
266 }
267 }
268 
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
FAMILY_SCRIPT
ImplFontAttrs Type
FAMILY_MODERN
FontWidth
FAMILY_DONTKNOW
void UpdateCloneFontList(PhysicalFontCollection &) const
WIDTH_NORMAL
PhysicalFontFamily(const OUString &rSearchName)
WEIGHT_SEMIBOLD
FAMILY_ROMAN
None
NONE
sal_uInt16 sal_Unicode
FontItalic GetItalic() const
FAMILY_DECORATIVE
WEIGHT_DONTKNOW
FontFamily GetFamilyType() const
static void CalcType(ImplFontAttrs &rType, FontWeight &rWeight, FontWidth &rWidth, FontFamily eFamily, const utl::FontNameAttr *pFontAttr)
WEIGHT_SEMILIGHT
FontWeight Weight
static ImplFontAttrs lcl_IsCJKFont(const OUString &rFontName)
int i
FontWeight GetWeight() const
ITALIC_OBLIQUE
ImplFontAttrs
void SetFamilyName(const OUString &sFamilyName)
std::vector< rtl::Reference< PhysicalFontFace > > maFontFaces
OUString GetEnglishSearchFontName(std::u16string_view rInName)
A PhysicalFontFaceCollection is created by a PhysicalFontCollection and becomes invalid when original...
void UpdateDevFontList(PhysicalFontFaceCollection &) const
WEIGHT_NORMAL
PITCH_DONTKNOW
PhysicalFontFace * FindBestFontFace(const vcl::font::FontSelectPattern &rFSD) const
int GetQuality() const
ITALIC_NONE
void InitMatchData(const utl::FontSubstConfiguration &, const OUString &rSearchName)
const OUString & GetMapNames() const
abstract base class for physical font faces
FontFamily
FontWeight
void AddFontFace(PhysicalFontFace *)
ITALIC_NORMAL
WIDTH_DONTKNOW
bool IsBetterMatch(const vcl::font::FontSelectPattern &, FontMatchStatus &) const
sal_Int32 CompareIgnoreSize(const PhysicalFontFace &) const
FAMILY_SWISS
bool IsSymbolFont() const
const OUString & GetFamilyName() const
FontPitch GetPitch() const
vcl::font::PhysicalFontFamily * FindOrCreateFontFamily(const OUString &rFamilyName)
const OUString & GetFamilyName() const