bump product version to 4.1.6.2
[LibreOffice.git] / vcl / generic / fontmanager / fontsubst.cxx
blob900125baa35f8a4d249039f7f339123a1c22980f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 "generic/geninst.h"
21 #include "generic/genpspgraphics.h"
22 #include "generic/glyphcache.hxx"
24 #include "vcl/sysdata.hxx"
25 #include "outfont.hxx"
27 #include "generic/printergfx.hxx"
28 #include "salbmp.hxx"
29 #include "impfont.hxx"
30 #include "outdev.h"
31 #include "fontsubset.hxx"
32 #include "salprn.hxx"
33 #include "region.h"
35 #include <list>
37 // ===========================================================================
38 // platform specific font substitution hooks
39 // ===========================================================================
41 struct FontSelectPatternAttributesHash
43 size_t operator()(const FontSelectPatternAttributes& rAttributes) const
44 { return rAttributes.hashCode(); }
47 class FcPreMatchSubstititution
48 : public ImplPreMatchFontSubstitution
50 public:
51 bool FindFontSubstitute( FontSelectPattern& ) const;
52 typedef ::std::pair<FontSelectPatternAttributes, FontSelectPatternAttributes> value_type;
53 private:
54 typedef ::std::list<value_type> CachedFontMapType;
55 mutable CachedFontMapType maCachedFontMap;
58 class FcGlyphFallbackSubstititution
59 : public ImplGlyphFallbackFontSubstitution
61 // TODO: add a cache
62 public:
63 bool FindFontSubstitute( FontSelectPattern&, OUString& rMissingCodes ) const;
66 int SalGenericInstance::FetchFontSubstitutionFlags()
68 // init font substitution defaults
69 int nDisableBits = 0;
70 #ifdef SOLARIS
71 nDisableBits = 1; // disable "font fallback" here on default
72 #endif
73 // apply the environment variable if any
74 const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
75 if( pEnvStr )
77 if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
78 nDisableBits = (*pEnvStr - '0');
79 else
80 nDisableBits = ~0U; // no specific bits set: disable all
82 return nDisableBits;
85 void SalGenericInstance::RegisterFontSubstitutors( ImplDevFontList* pList )
87 // init font substitution defaults
88 int nDisableBits = 0;
89 #ifdef SOLARIS
90 nDisableBits = 1; // disable "font fallback" here on default
91 #endif
92 // apply the environment variable if any
93 const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
94 if( pEnvStr )
96 if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
97 nDisableBits = (*pEnvStr - '0');
98 else
99 nDisableBits = ~0U; // no specific bits set: disable all
102 // register font fallback substitutions (unless disabled by bit0)
103 if( (nDisableBits & 1) == 0 )
105 static FcPreMatchSubstititution aSubstPreMatch;
106 pList->SetPreMatchHook( &aSubstPreMatch );
109 // register glyph fallback substitutions (unless disabled by bit1)
110 if( (nDisableBits & 2) == 0 )
112 static FcGlyphFallbackSubstititution aSubstFallback;
113 pList->SetFallbackHook( &aSubstFallback );
117 // -----------------------------------------------------------------------
119 static FontSelectPattern GetFcSubstitute(const FontSelectPattern &rFontSelData, OUString& rMissingCodes )
121 FontSelectPattern aSubstituted(rFontSelData);
122 psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
123 rMgr.Substitute(aSubstituted, rMissingCodes);
124 return aSubstituted;
127 namespace
129 bool uselessmatch(const FontSelectPattern &rOrig, const FontSelectPattern &rNew)
131 return
133 rOrig.maTargetName == rNew.maSearchName &&
134 rOrig.GetWeight() == rNew.GetWeight() &&
135 rOrig.GetSlant() == rNew.GetSlant() &&
136 rOrig.GetPitch() == rNew.GetPitch() &&
137 rOrig.GetWidthType() == rNew.GetWidthType()
141 class equal
143 private:
144 const FontSelectPatternAttributes& mrAttributes;
145 public:
146 equal(const FontSelectPatternAttributes& rAttributes)
147 : mrAttributes(rAttributes)
150 bool operator()(const FcPreMatchSubstititution::value_type& rOther) const
151 { return rOther.first == mrAttributes; }
155 //--------------------------------------------------------------------------
157 bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelData ) const
159 // We dont' actually want to talk to Fontconfig at all for symbol fonts
160 if( rFontSelData.IsSymbolFont() )
161 return false;
162 // StarSymbol is a unicode font, but it still deserves the symbol flag
163 if(rFontSelData.maSearchName.startsWithIgnoreAsciiCase( "starsymbol" )
164 || rFontSelData.maSearchName.startsWithIgnoreAsciiCase( "opensymbol" ) )
165 return false;
167 //see fdo#41556 and fdo#47636
168 //fontconfig can return e.g. an italic font for a non-italic input and/or
169 //different fonts depending on fontsize, bold, etc settings so don't cache
170 //just on the name, cache map all the input and all the output not just map
171 //from original selection to output fontname
172 FontSelectPatternAttributes& rPatternAttributes = rFontSelData;
173 CachedFontMapType &rCachedFontMap = const_cast<CachedFontMapType &>(maCachedFontMap);
174 CachedFontMapType::iterator itr = std::find_if(rCachedFontMap.begin(), rCachedFontMap.end(), equal(rPatternAttributes));
175 if (itr != rCachedFontMap.end())
177 // Cached substitution
178 rFontSelData.copyAttributes(itr->second);
179 if (itr != rCachedFontMap.begin())
181 // MRU, move it to the front
182 rCachedFontMap.splice(rCachedFontMap.begin(), rCachedFontMap, itr);
184 return true;
187 OUString aDummy;
188 const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, aDummy );
190 if( aOut.maSearchName.isEmpty() )
191 return false;
193 const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
195 #ifdef DEBUG
196 const OString aOrigName(OUStringToOString(rFontSelData.maTargetName,
197 RTL_TEXTENCODING_UTF8));
198 const OString aSubstName(OUStringToOString(aOut.maSearchName,
199 RTL_TEXTENCODING_UTF8));
200 printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
201 aOrigName.getStr(), rFontSelData.GetWeight(), rFontSelData.GetSlant(),
202 rFontSelData.GetPitch(), rFontSelData.GetWidthType() );
203 if( !bHaveSubstitute )
204 printf( "no substitute available\n" );
205 else
206 printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.getStr(),
207 aOut.GetWeight(), aOut.GetSlant(), aOut.GetPitch(), aOut.GetWidthType() );
208 #endif
210 if( bHaveSubstitute )
212 rCachedFontMap.push_front(value_type(rFontSelData, aOut));
213 //fairly arbitrary limit in this case, but I recall measuring max 8
214 //fonts as the typical max amount of fonts in medium sized documents
215 if (rCachedFontMap.size() > 8)
216 rCachedFontMap.pop_back();
217 rFontSelData = aOut;
220 return bHaveSubstitute;
223 // -----------------------------------------------------------------------
225 bool FcGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFontSelData,
226 OUString& rMissingCodes ) const
228 // We dont' actually want to talk to Fontconfig at all for symbol fonts
229 if( rFontSelData.IsSymbolFont() )
230 return false;
231 // StarSymbol is a unicode font, but it still deserves the symbol flag
232 if(rFontSelData.maSearchName.startsWithIgnoreAsciiCase( "starsymbol" )
233 || rFontSelData.maSearchName.startsWithIgnoreAsciiCase( "opensymbol" ) )
234 return false;
236 const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
237 // TODO: cache the unicode + srcfont specific result
238 // FC doing it would be preferable because it knows the invariables
239 // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
240 // whereas we would have to check for every size or attribute
241 if( aOut.maSearchName.isEmpty() )
242 return false;
244 const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
246 #ifdef DEBUG
247 const OString aOrigName(OUStringToOString(rFontSelData.maTargetName,
248 RTL_TEXTENCODING_UTF8));
249 const OString aSubstName(OUStringToOString(aOut.maSearchName,
250 RTL_TEXTENCODING_UTF8));
251 printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
252 aOrigName.getStr(), rFontSelData.GetWeight(), rFontSelData.GetSlant(),
253 rFontSelData.GetPitch(), rFontSelData.GetWidthType() );
254 if( !bHaveSubstitute )
255 printf( "no substitute available\n" );
256 else
257 printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.getStr(),
258 aOut.GetWeight(), aOut.GetSlant(), aOut.GetPitch(), aOut.GetWidthType() );
259 #endif
261 if( bHaveSubstitute )
262 rFontSelData = aOut;
264 return bHaveSubstitute;
267 // ===========================================================================
270 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */