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 <sal/config.h>
22 #include <unx/geninst.h>
23 #include <font/PhysicalFontCollection.hxx>
24 #include <font/fontsubstitution.hxx>
25 #include <unx/fontmanager.hxx>
27 // platform specific font substitution hooks
31 class FcPreMatchSubstitution
32 : public vcl::font::PreMatchFontSubstitution
35 bool FindFontSubstitute( vcl::font::FontSelectPattern
& ) const override
;
36 typedef ::std::pair
<vcl::font::FontSelectPattern
, vcl::font::FontSelectPattern
> value_type
;
38 typedef ::std::list
<value_type
> CachedFontMapType
;
39 mutable CachedFontMapType maCachedFontMap
;
42 class FcGlyphFallbackSubstitution
43 : public vcl::font::GlyphFallbackFontSubstitution
47 bool FindFontSubstitute(vcl::font::FontSelectPattern
&, LogicalFontInstance
* pLogicalFont
, OUString
& rMissingCodes
) const override
;
52 void SalGenericInstance::RegisterFontSubstitutors(vcl::font::PhysicalFontCollection
* pFontCollection
)
54 // register font fallback substitutions
55 static FcPreMatchSubstitution aSubstPreMatch
;
56 pFontCollection
->SetPreMatchHook( &aSubstPreMatch
);
58 // register glyph fallback substitutions
59 static FcGlyphFallbackSubstitution aSubstFallback
;
60 pFontCollection
->SetFallbackHook( &aSubstFallback
);
63 static vcl::font::FontSelectPattern
GetFcSubstitute(const vcl::font::FontSelectPattern
&rFontSelData
, OUString
& rMissingCodes
)
65 vcl::font::FontSelectPattern
aSubstituted(rFontSelData
);
66 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
67 rMgr
.Substitute(aSubstituted
, rMissingCodes
);
73 bool uselessmatch(const vcl::font::FontSelectPattern
&rOrig
, const vcl::font::FontSelectPattern
&rNew
)
77 rOrig
.maTargetName
== rNew
.maSearchName
&&
78 rOrig
.GetWeight() == rNew
.GetWeight() &&
79 rOrig
.GetItalic() == rNew
.GetItalic() &&
80 rOrig
.GetPitch() == rNew
.GetPitch() &&
81 rOrig
.GetWidthType() == rNew
.GetWidthType()
88 const vcl::font::FontSelectPattern
& mrAttributes
;
90 explicit equal(const vcl::font::FontSelectPattern
& rAttributes
)
91 : mrAttributes(rAttributes
)
94 bool operator()(const FcPreMatchSubstitution::value_type
& rOther
) const
95 { return rOther
.first
== mrAttributes
; }
99 bool FcPreMatchSubstitution::FindFontSubstitute(vcl::font::FontSelectPattern
&rFontSelData
) const
101 // We don't actually want to talk to Fontconfig at all for symbol fonts
102 if( rFontSelData
.IsMicrosoftSymbolEncoded() )
104 // OpenSymbol is a unicode font, but it still deserves to be treated as a symbol font
105 if ( IsOpenSymbol(rFontSelData
.maSearchName
) )
108 //see fdo#41556 and fdo#47636
109 //fontconfig can return e.g. an italic font for a non-italic input and/or
110 //different fonts depending on fontsize, bold, etc settings so don't cache
111 //just on the name, cache map all the input and all the output not just map
112 //from original selection to output fontname
113 vcl::font::FontSelectPattern
& rPatternAttributes
= rFontSelData
;
114 CachedFontMapType
&rCachedFontMap
= maCachedFontMap
;
115 CachedFontMapType::iterator itr
= std::find_if(rCachedFontMap
.begin(), rCachedFontMap
.end(), equal(rPatternAttributes
));
116 if (itr
!= rCachedFontMap
.end())
118 // Cached substitution
119 rFontSelData
= itr
->second
;
120 if (itr
!= rCachedFontMap
.begin())
122 // MRU, move it to the front
123 rCachedFontMap
.splice(rCachedFontMap
.begin(), rCachedFontMap
, itr
);
129 const vcl::font::FontSelectPattern aOut
= GetFcSubstitute( rFontSelData
, aDummy
);
131 if( aOut
.maSearchName
.isEmpty() )
134 const bool bHaveSubstitute
= !uselessmatch( rFontSelData
, aOut
);
136 #if OSL_DEBUG_LEVEL >= 2
137 std::ostringstream oss
;
138 oss
<< "FcPreMatchSubstitution \""
139 << rFontSelData
.maTargetName
141 << rFontSelData
.GetWeight()
142 << rFontSelData
.GetItalic()
143 << rFontSelData
.GetPitch()
144 << rFontSelData
.GetWidthType()
146 if( !bHaveSubstitute
)
147 oss
<< "no substitute available.";
155 << aOut
.GetWidthType();
156 SAL_INFO("vcl.fonts", oss
.str());
159 if( bHaveSubstitute
)
161 rCachedFontMap
.push_front(value_type(rFontSelData
, aOut
));
162 // Fairly arbitrary limit in this case, but I recall measuring max 8
163 // fonts as the typical max amount of fonts in medium sized documents, so make it
164 // a fair chunk larger to accommodate weird documents./
165 if (rCachedFontMap
.size() > 256)
166 rCachedFontMap
.pop_back();
170 return bHaveSubstitute
;
173 bool FcGlyphFallbackSubstitution::FindFontSubstitute(vcl::font::FontSelectPattern
& rFontSelData
,
174 LogicalFontInstance
* /*pLogicalFont*/,
175 OUString
& rMissingCodes
) const
177 // We don't actually want to talk to Fontconfig at all for symbol fonts
178 if( rFontSelData
.IsMicrosoftSymbolEncoded() )
180 // OpenSymbol is a unicode font, but it still deserves to be treated as a symbol font
181 if ( IsOpenSymbol(rFontSelData
.maSearchName
) )
184 const vcl::font::FontSelectPattern aOut
= GetFcSubstitute( rFontSelData
, rMissingCodes
);
185 // TODO: cache the unicode + srcfont specific result
186 // FC doing it would be preferable because it knows the invariables
187 // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
188 // whereas we would have to check for every size or attribute
189 if( aOut
.maSearchName
.isEmpty() )
192 const bool bHaveSubstitute
= !uselessmatch( rFontSelData
, aOut
);
194 #if OSL_DEBUG_LEVEL >= 2
195 std::ostringstream oss
;
196 oss
<< "FcGFSubstitution \""
197 << rFontSelData
.maTargetName
199 << rFontSelData
.GetWeight()
200 << rFontSelData
.GetItalic()
201 << rFontSelData
.GetPitch()
202 << rFontSelData
.GetWidthType()
204 if( !bHaveSubstitute
)
205 oss
<< "no substitute available.";
213 << aOut
.GetWidthType();
214 SAL_INFO("vcl.fonts", oss
.str());
217 if( bHaveSubstitute
)
220 return bHaveSubstitute
;
223 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */