Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "generic/geninst.h"
21 : #include "generic/genpspgraphics.h"
22 : #include "generic/glyphcache.hxx"
23 :
24 : #include "vcl/sysdata.hxx"
25 : #include "outfont.hxx"
26 :
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"
34 :
35 : #include <unotools/fontdefs.hxx>
36 : #include <list>
37 :
38 : // platform specific font substitution hooks
39 :
40 0 : class FcPreMatchSubstititution
41 : : public ImplPreMatchFontSubstitution
42 : {
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;
49 : };
50 :
51 0 : class FcGlyphFallbackSubstititution
52 : : public ImplGlyphFallbackFontSubstitution
53 : {
54 : // TODO: add a cache
55 : public:
56 : bool FindFontSubstitute( FontSelectPattern&, OUString& rMissingCodes ) const SAL_OVERRIDE;
57 : };
58 :
59 0 : int SalGenericInstance::FetchFontSubstitutionFlags()
60 : {
61 : // init font substitution defaults
62 0 : 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 0 : const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
68 0 : if( pEnvStr )
69 : {
70 0 : if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
71 0 : nDisableBits = (*pEnvStr - '0');
72 : else
73 0 : nDisableBits = ~0U; // no specific bits set: disable all
74 : }
75 0 : return nDisableBits;
76 : }
77 :
78 0 : void SalGenericInstance::RegisterFontSubstitutors( PhysicalFontCollection* pFontCollection )
79 : {
80 : // init font substitution defaults
81 0 : 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 0 : const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
87 0 : if( pEnvStr )
88 : {
89 0 : if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
90 0 : nDisableBits = (*pEnvStr - '0');
91 : else
92 0 : nDisableBits = ~0U; // no specific bits set: disable all
93 : }
94 :
95 : // register font fallback substitutions (unless disabled by bit0)
96 0 : if( (nDisableBits & 1) == 0 )
97 : {
98 0 : static FcPreMatchSubstititution aSubstPreMatch;
99 0 : pFontCollection->SetPreMatchHook( &aSubstPreMatch );
100 : }
101 :
102 : // register glyph fallback substitutions (unless disabled by bit1)
103 0 : if( (nDisableBits & 2) == 0 )
104 : {
105 0 : static FcGlyphFallbackSubstititution aSubstFallback;
106 0 : pFontCollection->SetFallbackHook( &aSubstFallback );
107 : }
108 0 : }
109 :
110 0 : static FontSelectPattern GetFcSubstitute(const FontSelectPattern &rFontSelData, OUString& rMissingCodes )
111 : {
112 0 : FontSelectPattern aSubstituted(rFontSelData);
113 0 : psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
114 0 : rMgr.Substitute(aSubstituted, rMissingCodes);
115 0 : return aSubstituted;
116 : }
117 :
118 : namespace
119 : {
120 0 : bool uselessmatch(const FontSelectPattern &rOrig, const FontSelectPattern &rNew)
121 : {
122 : return
123 : (
124 0 : rOrig.maTargetName == rNew.maSearchName &&
125 0 : rOrig.GetWeight() == rNew.GetWeight() &&
126 0 : rOrig.GetSlant() == rNew.GetSlant() &&
127 0 : rOrig.GetPitch() == rNew.GetPitch() &&
128 0 : rOrig.GetWidthType() == rNew.GetWidthType()
129 0 : );
130 : }
131 :
132 : class equal
133 : {
134 : private:
135 : const FontSelectPatternAttributes& mrAttributes;
136 : public:
137 0 : equal(const FontSelectPatternAttributes& rAttributes)
138 0 : : mrAttributes(rAttributes)
139 : {
140 0 : }
141 0 : bool operator()(const FcPreMatchSubstititution::value_type& rOther) const
142 0 : { return rOther.first == mrAttributes; }
143 : };
144 : }
145 :
146 0 : bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelData ) const
147 : {
148 : // We don't actually want to talk to Fontconfig at all for symbol fonts
149 0 : if( rFontSelData.IsSymbolFont() )
150 0 : return false;
151 : // StarSymbol is a unicode font, but it still deserves the symbol flag
152 0 : if ( IsStarSymbol(rFontSelData.maSearchName) )
153 0 : return false;
154 :
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 0 : FontSelectPatternAttributes& rPatternAttributes = rFontSelData;
161 0 : CachedFontMapType &rCachedFontMap = const_cast<CachedFontMapType &>(maCachedFontMap);
162 0 : CachedFontMapType::iterator itr = std::find_if(rCachedFontMap.begin(), rCachedFontMap.end(), equal(rPatternAttributes));
163 0 : if (itr != rCachedFontMap.end())
164 : {
165 : // Cached substitution
166 0 : rFontSelData.copyAttributes(itr->second);
167 0 : if (itr != rCachedFontMap.begin())
168 : {
169 : // MRU, move it to the front
170 0 : rCachedFontMap.splice(rCachedFontMap.begin(), rCachedFontMap, itr);
171 : }
172 0 : return true;
173 : }
174 :
175 0 : OUString aDummy;
176 0 : const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, aDummy );
177 :
178 0 : if( aOut.maSearchName.isEmpty() )
179 0 : return false;
180 :
181 0 : const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
182 :
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
197 :
198 0 : if( bHaveSubstitute )
199 : {
200 0 : 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 0 : if (rCachedFontMap.size() > 8)
204 0 : rCachedFontMap.pop_back();
205 0 : rFontSelData = aOut;
206 : }
207 :
208 0 : return bHaveSubstitute;
209 : }
210 :
211 0 : bool FcGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFontSelData,
212 : OUString& rMissingCodes ) const
213 : {
214 : // We don't actually want to talk to Fontconfig at all for symbol fonts
215 0 : if( rFontSelData.IsSymbolFont() )
216 0 : return false;
217 : // StarSymbol is a unicode font, but it still deserves the symbol flag
218 0 : if ( IsStarSymbol(rFontSelData.maSearchName) )
219 0 : return false;
220 :
221 0 : 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 0 : if( aOut.maSearchName.isEmpty() )
227 0 : return false;
228 :
229 0 : const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
230 :
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
245 :
246 0 : if( bHaveSubstitute )
247 0 : rFontSelData = aOut;
248 :
249 0 : return bHaveSubstitute;
250 3 : }
251 :
252 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|