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
>= 0x3130) && (ch
<= 0x318F)) ||
71 ((ch
>= 0x1100) && (ch
<= 0x11FF)) )
72 return ImplFontAttrs::CJK
|ImplFontAttrs::CJK_KR
;
75 if ( ((ch
>= 0x3400) && (ch
<= 0x9FFF)) )
76 return ImplFontAttrs::CJK
|ImplFontAttrs::CJK_TC
|ImplFontAttrs::CJK_SC
;
79 if ( ((ch
>= 0x3000) && (ch
<= 0xD7AF)) ||
80 ((ch
>= 0xFF00) && (ch
<= 0xFFEE)) )
81 return ImplFontAttrs::CJK
;
85 return ImplFontAttrs::None
;
88 PhysicalFontFamily::PhysicalFontFamily( const OUString
& rSearchName
)
89 : maSearchName( rSearchName
),
90 mnTypeFaces( FontTypeFaces::NONE
),
91 meFamily( FAMILY_DONTKNOW
),
92 mePitch( PITCH_DONTKNOW
),
94 mnMatchType( ImplFontAttrs::None
),
95 meMatchWeight( WEIGHT_DONTKNOW
),
96 meMatchWidth( WIDTH_DONTKNOW
)
99 PhysicalFontFamily::~PhysicalFontFamily()
101 // release all physical font faces
102 for( std::vector
< PhysicalFontFace
* >::iterator it
=maFontFaces
.begin(); it
!= maFontFaces
.end(); )
105 it
= maFontFaces
.erase( it
);
110 bool PhysicalFontFamily::AddFontFace( PhysicalFontFace
* pNewFontFace
)
112 if( maFontFaces
.empty() )
114 maFamilyName
= pNewFontFace
->GetFamilyName();
115 maMapNames
= pNewFontFace
->GetMapNames();
116 meFamily
= pNewFontFace
->GetFamilyType();
117 mePitch
= pNewFontFace
->GetPitch();
118 mnMinQuality
= pNewFontFace
->GetQuality();
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();
130 // set attributes for attribute based font matching
131 mnTypeFaces
|= FontTypeFaces::Scalable
;
133 if( pNewFontFace
->IsSymbolFont() )
134 mnTypeFaces
|= FontTypeFaces::Symbol
;
136 mnTypeFaces
|= FontTypeFaces::NoneSymbol
;
138 if( pNewFontFace
->GetWeight() != WEIGHT_DONTKNOW
)
140 if( pNewFontFace
->GetWeight() >= WEIGHT_SEMIBOLD
)
141 mnTypeFaces
|= FontTypeFaces::Bold
;
142 else if( pNewFontFace
->GetWeight() <= WEIGHT_SEMILIGHT
)
143 mnTypeFaces
|= FontTypeFaces::Light
;
145 mnTypeFaces
|= FontTypeFaces::Normal
;
148 if( pNewFontFace
->GetItalic() == ITALIC_NONE
)
149 mnTypeFaces
|= FontTypeFaces::NoneItalic
;
150 else if( (pNewFontFace
->GetItalic() == ITALIC_NORMAL
)
151 || (pNewFontFace
->GetItalic() == ITALIC_OBLIQUE
) )
152 mnTypeFaces
|= FontTypeFaces::Italic
;
154 // reassign name (sharing saves memory)
155 if( pNewFontFace
->GetFamilyName() == GetFamilyName() )
156 pNewFontFace
->SetFamilyName( GetFamilyName() );
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
)
163 PhysicalFontFace
* pFoundFontFace
= *it
;
164 sal_Int32 eComp
= pNewFontFace
->CompareWithSize( *pFoundFontFace
);
170 // ignore duplicate if its quality is worse
171 if( pNewFontFace
->GetQuality() < pFoundFontFace
->GetQuality() )
174 // keep the device font if its quality is good enough
175 if( pNewFontFace
->GetQuality() == pFoundFontFace
->GetQuality() )
178 // replace existing font face with a better one
179 delete pFoundFontFace
;
180 *it
= pNewFontFace
; // insert at sort position
184 maFontFaces
.insert(it
, pNewFontFace
); // insert at sort position
188 // get font attributes using the normalized font family name
189 void PhysicalFontFamily::InitMatchData( const utl::FontSubstConfiguration
& rFontSubst
,
190 const OUString
& rSearchName
)
193 OUString
aMatchFamilyName(maMatchFamilyName
);
194 // get font attributes from the decorated font name
195 utl::FontSubstConfiguration::getMapName( rSearchName
, aShortName
, aMatchFamilyName
,
196 meMatchWeight
, meMatchWidth
, mnMatchType
);
197 maMatchFamilyName
= aMatchFamilyName
;
198 const utl::FontNameAttr
* pFontAttr
= rFontSubst
.getSubstInfo( rSearchName
);
199 // eventually use the stripped name
201 if( aShortName
!= rSearchName
)
202 pFontAttr
= rFontSubst
.getSubstInfo( aShortName
);
203 CalcType( mnMatchType
, meMatchWeight
, meMatchWidth
, meFamily
, pFontAttr
);
204 mnMatchType
|= lcl_IsCJKFont( maFamilyName
);
207 PhysicalFontFace
* PhysicalFontFamily::FindBestFontFace( const FontSelectPattern
& rFSD
) const
209 if( maFontFaces
.empty() )
211 if( maFontFaces
.size() == 1)
212 return maFontFaces
[0];
214 // FontName+StyleName should map to FamilyName+StyleName
215 const OUString
& rSearchName
= rFSD
.maTargetName
;
216 OUString aTargetStyleName
;
217 const OUString
* pTargetStyleName
= nullptr;
218 if((rSearchName
.getLength() > maSearchName
.getLength())
219 && rSearchName
.startsWith( maSearchName
) )
221 aTargetStyleName
= rSearchName
.copy(maSearchName
.getLength() + 1);
222 pTargetStyleName
= &aTargetStyleName
;
225 // TODO: linear search improve!
226 PhysicalFontFace
* pBestFontFace
= maFontFaces
[0];
227 FontMatchStatus aFontMatchStatus
= {0,0,0, pTargetStyleName
};
228 for( std::vector
< PhysicalFontFace
* >::const_iterator it
=maFontFaces
.begin(); it
!= maFontFaces
.end(); ++it
)
230 PhysicalFontFace
* pFoundFontFace
= *it
;
231 if( pFoundFontFace
->IsBetterMatch( rFSD
, aFontMatchStatus
) )
232 pBestFontFace
= pFoundFontFace
;
235 return pBestFontFace
;
238 // update device font list with unique font faces, with uniqueness
239 // meaning different font attributes, but not different fonts sizes
240 void PhysicalFontFamily::UpdateDevFontList( ImplDeviceFontList
& rDevFontList
) const
242 PhysicalFontFace
* pPrevFace
= nullptr;
243 for(std::vector
< PhysicalFontFace
* >::const_iterator it
=maFontFaces
.begin(); it
!= maFontFaces
.end(); ++it
)
245 PhysicalFontFace
* pFoundFontFace
= *it
;
246 if( !pPrevFace
|| pFoundFontFace
->CompareIgnoreSize( *pPrevFace
) )
247 rDevFontList
.Add( pFoundFontFace
);
248 pPrevFace
= pFoundFontFace
;
252 void PhysicalFontFamily::GetFontHeights( std::set
<int>& rHeights
) const
254 // add all available font heights
255 for( std::vector
< PhysicalFontFace
* >::const_iterator it
=maFontFaces
.begin(); it
!= maFontFaces
.end(); ++it
)
257 PhysicalFontFace
*pFoundFontFace
= *it
;
258 rHeights
.insert( pFoundFontFace
->GetHeight() );
262 void PhysicalFontFamily::UpdateCloneFontList(PhysicalFontCollection
& rFontCollection
) const
264 OUString aFamilyName
= GetEnglishSearchFontName( GetFamilyName() );
265 PhysicalFontFamily
* pFamily(nullptr);
267 for( std::vector
< PhysicalFontFace
* >::const_iterator it
=maFontFaces
.begin(); it
!= maFontFaces
.end(); ++it
)
269 PhysicalFontFace
*pFoundFontFace
= *it
;
272 { // tdf#98989 lazy create as family without faces won't work
273 pFamily
= rFontCollection
.FindOrCreateFontFamily(aFamilyName
);
276 PhysicalFontFace
* pClonedFace
= pFoundFontFace
->Clone();
278 #if OSL_DEBUG_LEVEL > 0
279 OUString aClonedFamilyName
= GetEnglishSearchFontName( pClonedFace
->GetFamilyName() );
280 assert( aClonedFamilyName
== aFamilyName
);
281 assert( rFontCollection
.FindOrCreateFontFamily( aClonedFamilyName
) == pFamily
);
284 if (! pFamily
->AddFontFace( pClonedFace
) )
289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */