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