Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / generic / fontmanager / fontsubst.cxx
blob8ac1e1e54221d35175ec74b2250548c846b11c36
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 "PhysicalFontCollection.hxx"
32 #include "fontsubset.hxx"
33 #include "salprn.hxx"
35 #include <unotools/fontdefs.hxx>
36 #include <list>
38 // platform specific font substitution hooks
40 class FcPreMatchSubstititution
41 : public ImplPreMatchFontSubstitution
43 public:
44 bool FindFontSubstitute( FontSelectPattern& ) const SAL_OVERRIDE;
45 typedef ::std::pair<FontSelectPatternAttributes, FontSelectPatternAttributes> value_type;
46 private:
47 typedef ::std::list<value_type> CachedFontMapType;
48 mutable CachedFontMapType maCachedFontMap;
51 class FcGlyphFallbackSubstititution
52 : public ImplGlyphFallbackFontSubstitution
54 // TODO: add a cache
55 public:
56 bool FindFontSubstitute( FontSelectPattern&, OUString& rMissingCodes ) const SAL_OVERRIDE;
59 int SalGenericInstance::FetchFontSubstitutionFlags()
61 // init font substitution defaults
62 int nDisableBits = 0;
63 #ifdef SOLARIS
64 nDisableBits = 1; // disable "font fallback" here on default
65 #endif
66 // apply the environment variable if any
67 const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
68 if( pEnvStr )
70 if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
71 nDisableBits = (*pEnvStr - '0');
72 else
73 nDisableBits = ~0U; // no specific bits set: disable all
75 return nDisableBits;
78 void SalGenericInstance::RegisterFontSubstitutors( PhysicalFontCollection* pFontCollection )
80 // init font substitution defaults
81 int nDisableBits = 0;
82 #ifdef SOLARIS
83 nDisableBits = 1; // disable "font fallback" here on default
84 #endif
85 // apply the environment variable if any
86 const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
87 if( pEnvStr )
89 if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
90 nDisableBits = (*pEnvStr - '0');
91 else
92 nDisableBits = ~0U; // no specific bits set: disable all
95 // register font fallback substitutions (unless disabled by bit0)
96 if( (nDisableBits & 1) == 0 )
98 static FcPreMatchSubstititution aSubstPreMatch;
99 pFontCollection->SetPreMatchHook( &aSubstPreMatch );
102 // register glyph fallback substitutions (unless disabled by bit1)
103 if( (nDisableBits & 2) == 0 )
105 static FcGlyphFallbackSubstititution aSubstFallback;
106 pFontCollection->SetFallbackHook( &aSubstFallback );
110 static FontSelectPattern GetFcSubstitute(const FontSelectPattern &rFontSelData, OUString& rMissingCodes )
112 FontSelectPattern aSubstituted(rFontSelData);
113 psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
114 rMgr.Substitute(aSubstituted, rMissingCodes);
115 return aSubstituted;
118 namespace
120 bool uselessmatch(const FontSelectPattern &rOrig, const FontSelectPattern &rNew)
122 return
124 rOrig.maTargetName == rNew.maSearchName &&
125 rOrig.GetWeight() == rNew.GetWeight() &&
126 rOrig.GetSlant() == rNew.GetSlant() &&
127 rOrig.GetPitch() == rNew.GetPitch() &&
128 rOrig.GetWidthType() == rNew.GetWidthType()
132 class equal
134 private:
135 const FontSelectPatternAttributes& mrAttributes;
136 public:
137 equal(const FontSelectPatternAttributes& rAttributes)
138 : mrAttributes(rAttributes)
141 bool operator()(const FcPreMatchSubstititution::value_type& rOther) const
142 { return rOther.first == mrAttributes; }
146 bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelData ) const
148 // We don't actually want to talk to Fontconfig at all for symbol fonts
149 if( rFontSelData.IsSymbolFont() )
150 return false;
151 // StarSymbol is a unicode font, but it still deserves the symbol flag
152 if ( IsStarSymbol(rFontSelData.maSearchName) )
153 return false;
155 //see fdo#41556 and fdo#47636
156 //fontconfig can return e.g. an italic font for a non-italic input and/or
157 //different fonts depending on fontsize, bold, etc settings so don't cache
158 //just on the name, cache map all the input and all the output not just map
159 //from original selection to output fontname
160 FontSelectPatternAttributes& rPatternAttributes = rFontSelData;
161 CachedFontMapType &rCachedFontMap = const_cast<CachedFontMapType &>(maCachedFontMap);
162 CachedFontMapType::iterator itr = std::find_if(rCachedFontMap.begin(), rCachedFontMap.end(), equal(rPatternAttributes));
163 if (itr != rCachedFontMap.end())
165 // Cached substitution
166 rFontSelData.copyAttributes(itr->second);
167 if (itr != rCachedFontMap.begin())
169 // MRU, move it to the front
170 rCachedFontMap.splice(rCachedFontMap.begin(), rCachedFontMap, itr);
172 return true;
175 OUString aDummy;
176 const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, aDummy );
178 if( aOut.maSearchName.isEmpty() )
179 return false;
181 const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
183 #ifdef DEBUG
184 const OString aOrigName(OUStringToOString(rFontSelData.maTargetName,
185 RTL_TEXTENCODING_UTF8));
186 const OString aSubstName(OUStringToOString(aOut.maSearchName,
187 RTL_TEXTENCODING_UTF8));
188 printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
189 aOrigName.getStr(), rFontSelData.GetWeight(), rFontSelData.GetSlant(),
190 rFontSelData.GetPitch(), rFontSelData.GetWidthType() );
191 if( !bHaveSubstitute )
192 printf( "no substitute available\n" );
193 else
194 printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.getStr(),
195 aOut.GetWeight(), aOut.GetSlant(), aOut.GetPitch(), aOut.GetWidthType() );
196 #endif
198 if( bHaveSubstitute )
200 rCachedFontMap.push_front(value_type(rFontSelData, aOut));
201 //fairly arbitrary limit in this case, but I recall measuring max 8
202 //fonts as the typical max amount of fonts in medium sized documents
203 if (rCachedFontMap.size() > 8)
204 rCachedFontMap.pop_back();
205 rFontSelData = aOut;
208 return bHaveSubstitute;
211 bool FcGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFontSelData,
212 OUString& rMissingCodes ) const
214 // We don't actually want to talk to Fontconfig at all for symbol fonts
215 if( rFontSelData.IsSymbolFont() )
216 return false;
217 // StarSymbol is a unicode font, but it still deserves the symbol flag
218 if ( IsStarSymbol(rFontSelData.maSearchName) )
219 return false;
221 const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
222 // TODO: cache the unicode + srcfont specific result
223 // FC doing it would be preferable because it knows the invariables
224 // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
225 // whereas we would have to check for every size or attribute
226 if( aOut.maSearchName.isEmpty() )
227 return false;
229 const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
231 #ifdef DEBUG
232 const OString aOrigName(OUStringToOString(rFontSelData.maTargetName,
233 RTL_TEXTENCODING_UTF8));
234 const OString aSubstName(OUStringToOString(aOut.maSearchName,
235 RTL_TEXTENCODING_UTF8));
236 printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
237 aOrigName.getStr(), rFontSelData.GetWeight(), rFontSelData.GetSlant(),
238 rFontSelData.GetPitch(), rFontSelData.GetWidthType() );
239 if( !bHaveSubstitute )
240 printf( "no substitute available\n" );
241 else
242 printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.getStr(),
243 aOut.GetWeight(), aOut.GetSlant(), aOut.GetPitch(), aOut.GetWidthType() );
244 #endif
246 if( bHaveSubstitute )
247 rFontSelData = aOut;
249 return bHaveSubstitute;
252 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */