1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <rtl/ustring.hxx>
21 #include <unotools/fontdefs.hxx>
24 #include <PhysicalFontCollection.hxx>
26 void PhysicalFontFamily::CalcType( ImplFontAttrs
& rType
, FontWeight
& rWeight
, FontWidth
& rWidth
,
27 FontFamily eFamily
, const utl::FontNameAttr
* pFontAttr
)
29 if ( eFamily
!= FAMILY_DONTKNOW
)
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
;
45 rType
|= pFontAttr
->Type
;
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
;
56 static ImplFontAttrs
lcl_IsCJKFont( const OUString
& rFontName
)
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
++)
62 const sal_Unicode ch
= rFontName
[i
];
64 if ( ((ch
>= 0x3040) && (ch
<= 0x30FF)) ||
65 ((ch
>= 0x3190) && (ch
<= 0x319F)) )
66 return ImplFontAttrs::CJK
|ImplFontAttrs::CJK_JP
;
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
;
77 if ( (ch
>= 0x3400) && (ch
<= 0x9FFF) )
78 return ImplFontAttrs::CJK
|ImplFontAttrs::CJK_TC
|ImplFontAttrs::CJK_SC
;
81 if ( ((ch
>= 0x3000) && (ch
<= 0xD7AF)) ||
82 ((ch
>= 0xFF00) && (ch
<= 0xFFEE)) )
83 return ImplFontAttrs::CJK
;
87 return ImplFontAttrs::None
;
90 PhysicalFontFamily::PhysicalFontFamily( const OUString
& rSearchName
)
91 : maSearchName( rSearchName
),
92 mnTypeFaces( FontTypeFaces::NONE
),
93 meFamily( FAMILY_DONTKNOW
),
94 mePitch( PITCH_DONTKNOW
),
96 mnMatchType( ImplFontAttrs::None
),
97 meMatchWeight( WEIGHT_DONTKNOW
),
98 meMatchWidth( WIDTH_DONTKNOW
)
101 PhysicalFontFamily::~PhysicalFontFamily()
105 void PhysicalFontFamily::AddFontFace( PhysicalFontFace
* pNewFontFace
)
107 if( maFontFaces
.empty() )
109 maFamilyName
= pNewFontFace
->GetFamilyName();
110 maMapNames
= pNewFontFace
->GetMapNames();
111 meFamily
= pNewFontFace
->GetFamilyType();
112 mePitch
= pNewFontFace
->GetPitch();
113 mnMinQuality
= pNewFontFace
->GetQuality();
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();
125 // set attributes for attribute based font matching
126 mnTypeFaces
|= FontTypeFaces::Scalable
;
128 if( pNewFontFace
->IsSymbolFont() )
129 mnTypeFaces
|= FontTypeFaces::Symbol
;
131 mnTypeFaces
|= FontTypeFaces::NoneSymbol
;
133 if( pNewFontFace
->GetWeight() != WEIGHT_DONTKNOW
)
135 if( pNewFontFace
->GetWeight() >= WEIGHT_SEMIBOLD
)
136 mnTypeFaces
|= FontTypeFaces::Bold
;
137 else if( pNewFontFace
->GetWeight() <= WEIGHT_SEMILIGHT
)
138 mnTypeFaces
|= FontTypeFaces::Light
;
140 mnTypeFaces
|= FontTypeFaces::Normal
;
143 if( pNewFontFace
->GetItalic() == ITALIC_NONE
)
144 mnTypeFaces
|= FontTypeFaces::NoneItalic
;
145 else if( (pNewFontFace
->GetItalic() == ITALIC_NORMAL
)
146 || (pNewFontFace
->GetItalic() == ITALIC_OBLIQUE
) )
147 mnTypeFaces
|= FontTypeFaces::Italic
;
149 // reassign name (sharing saves memory)
150 if( pNewFontFace
->GetFamilyName() == GetFamilyName() )
151 pNewFontFace
->SetFamilyName( GetFamilyName() );
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
)
158 PhysicalFontFace
* pFoundFontFace
= it
->get();
159 sal_Int32 eComp
= pNewFontFace
->CompareWithSize( *pFoundFontFace
);
165 // ignore duplicate if its quality is worse
166 if( pNewFontFace
->GetQuality() < pFoundFontFace
->GetQuality() )
169 // keep the device font if its quality is good enough
170 if( pNewFontFace
->GetQuality() == pFoundFontFace
->GetQuality() )
173 // replace existing font face with a better one
174 *it
= pNewFontFace
; // insert at sort position
178 maFontFaces
.emplace(it
, pNewFontFace
); // insert at sort position
181 // get font attributes using the normalized font family name
182 void PhysicalFontFamily::InitMatchData( const utl::FontSubstConfiguration
& rFontSubst
,
183 const OUString
& rSearchName
)
186 OUString
aMatchFamilyName(maMatchFamilyName
);
187 // get font attributes from the decorated font name
188 utl::FontSubstConfiguration::getMapName( rSearchName
, aShortName
, aMatchFamilyName
,
189 meMatchWeight
, meMatchWidth
, mnMatchType
);
190 maMatchFamilyName
= aMatchFamilyName
;
191 const utl::FontNameAttr
* pFontAttr
= rFontSubst
.getSubstInfo( rSearchName
);
192 // eventually use the stripped name
194 if( aShortName
!= rSearchName
)
195 pFontAttr
= rFontSubst
.getSubstInfo( aShortName
);
196 CalcType( mnMatchType
, meMatchWeight
, meMatchWidth
, meFamily
, pFontAttr
);
197 mnMatchType
|= lcl_IsCJKFont( maFamilyName
);
200 PhysicalFontFace
* PhysicalFontFamily::FindBestFontFace( const FontSelectPattern
& rFSD
) const
202 if( maFontFaces
.empty() )
204 if( maFontFaces
.size() == 1)
205 return maFontFaces
[0].get();
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
) )
214 aTargetStyleName
= rSearchName
.copy(maSearchName
.getLength() + 1);
215 pTargetStyleName
= &aTargetStyleName
;
218 // TODO: linear search improve!
219 PhysicalFontFace
* pBestFontFace
= maFontFaces
[0].get();
220 FontMatchStatus aFontMatchStatus
= {0,0,0, pTargetStyleName
};
221 for (auto const& font
: maFontFaces
)
223 PhysicalFontFace
* pFoundFontFace
= font
.get();
224 if( pFoundFontFace
->IsBetterMatch( rFSD
, aFontMatchStatus
) )
225 pBestFontFace
= pFoundFontFace
;
228 return pBestFontFace
;
231 // update device font list with unique font faces, with uniqueness
232 // meaning different font attributes, but not different fonts sizes
233 void PhysicalFontFamily::UpdateDevFontList( ImplDeviceFontList
& rDevFontList
) const
235 PhysicalFontFace
* pPrevFace
= nullptr;
236 for (auto const& font
: maFontFaces
)
238 PhysicalFontFace
* pFoundFontFace
= font
.get();
239 if( !pPrevFace
|| pFoundFontFace
->CompareIgnoreSize( *pPrevFace
) )
240 rDevFontList
.Add( pFoundFontFace
);
241 pPrevFace
= pFoundFontFace
;
245 void PhysicalFontFamily::GetFontHeights( std::set
<int>& rHeights
) const
247 // add all available font heights
248 for (auto const& font
: maFontFaces
)
250 PhysicalFontFace
*pFoundFontFace
= font
.get();
251 rHeights
.insert( pFoundFontFace
->GetHeight() );
255 void PhysicalFontFamily::UpdateCloneFontList(PhysicalFontCollection
& rFontCollection
) const
257 OUString aFamilyName
= GetEnglishSearchFontName( GetFamilyName() );
258 PhysicalFontFamily
* pFamily(nullptr);
260 for (auto const& font
: maFontFaces
)
262 PhysicalFontFace
*pFoundFontFace
= font
.get();
265 { // tdf#98989 lazy create as family without faces won't work
266 pFamily
= rFontCollection
.FindOrCreateFontFamily(aFamilyName
);
269 pFamily
->AddFontFace( pFoundFontFace
);
273 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */