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