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 "outfont.hxx"
31 : #include "outdev.h"
32 : #include "fontsubset.hxx"
33 : #include "salprn.hxx"
34 : #include "region.h"
35 :
36 : #include <list>
37 :
38 : // ===========================================================================
39 : // platform specific font substitution hooks
40 : // ===========================================================================
41 :
42 : struct FontSelectPatternAttributesHash
43 : {
44 : size_t operator()(const FontSelectPatternAttributes& rAttributes) const
45 : { return rAttributes.hashCode(); }
46 : };
47 :
48 40 : class FcPreMatchSubstititution
49 : : public ImplPreMatchFontSubstitution
50 : {
51 : public:
52 : bool FindFontSubstitute( FontSelectPattern& ) const;
53 : typedef ::std::pair<FontSelectPatternAttributes, FontSelectPatternAttributes> value_type;
54 : private:
55 : typedef ::std::list<value_type> CachedFontMapType;
56 : mutable CachedFontMapType maCachedFontMap;
57 : };
58 :
59 20 : class FcGlyphFallbackSubstititution
60 : : public ImplGlyphFallbackFontSubstitution
61 : {
62 : // TODO: add a cache
63 : public:
64 : bool FindFontSubstitute( FontSelectPattern&, rtl::OUString& rMissingCodes ) const;
65 : };
66 :
67 20 : int SalGenericInstance::FetchFontSubstitutionFlags()
68 : {
69 : // init font substitution defaults
70 20 : int nDisableBits = 0;
71 : #ifdef SOLARIS
72 : nDisableBits = 1; // disable "font fallback" here on default
73 : #endif
74 : // apply the environment variable if any
75 20 : const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
76 20 : if( pEnvStr )
77 : {
78 0 : if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
79 0 : nDisableBits = (*pEnvStr - '0');
80 : else
81 0 : nDisableBits = ~0U; // no specific bits set: disable all
82 : }
83 20 : return nDisableBits;
84 : }
85 :
86 23 : void SalGenericInstance::RegisterFontSubstitutors( ImplDevFontList* pList )
87 : {
88 : // init font substitution defaults
89 23 : int nDisableBits = 0;
90 : #ifdef SOLARIS
91 : nDisableBits = 1; // disable "font fallback" here on default
92 : #endif
93 : // apply the environment variable if any
94 23 : const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
95 23 : if( pEnvStr )
96 : {
97 0 : if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
98 0 : nDisableBits = (*pEnvStr - '0');
99 : else
100 0 : nDisableBits = ~0U; // no specific bits set: disable all
101 : }
102 :
103 : // register font fallback substitutions (unless disabled by bit0)
104 23 : if( (nDisableBits & 1) == 0 )
105 : {
106 23 : static FcPreMatchSubstititution aSubstPreMatch;
107 23 : pList->SetPreMatchHook( &aSubstPreMatch );
108 : }
109 :
110 : // register glyph fallback substitutions (unless disabled by bit1)
111 23 : if( (nDisableBits & 2) == 0 )
112 : {
113 23 : static FcGlyphFallbackSubstititution aSubstFallback;
114 23 : pList->SetFallbackHook( &aSubstFallback );
115 : }
116 23 : }
117 :
118 : // -----------------------------------------------------------------------
119 :
120 3852 : static FontSelectPattern GetFcSubstitute(const FontSelectPattern &rFontSelData, rtl::OUString& rMissingCodes )
121 : {
122 3852 : FontSelectPattern aSubstituted(rFontSelData);
123 3852 : psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
124 3852 : rMgr.Substitute(aSubstituted, rMissingCodes);
125 3852 : return aSubstituted;
126 : }
127 :
128 : namespace
129 : {
130 3852 : bool uselessmatch(const FontSelectPattern &rOrig, const FontSelectPattern &rNew)
131 : {
132 : return
133 : (
134 3852 : rOrig.maTargetName == rNew.maSearchName &&
135 : rOrig.meWeight == rNew.meWeight &&
136 : rOrig.meItalic == rNew.meItalic &&
137 : rOrig.mePitch == rNew.mePitch &&
138 : rOrig.meWidthType == rNew.meWidthType
139 3852 : );
140 : }
141 :
142 : class equal
143 : {
144 : private:
145 : const FontSelectPatternAttributes& mrAttributes;
146 : public:
147 33841 : equal(const FontSelectPatternAttributes& rAttributes)
148 33841 : : mrAttributes(rAttributes)
149 : {
150 33841 : }
151 91037 : bool operator()(const FcPreMatchSubstititution::value_type& rOther) const
152 91037 : { return rOther.first == mrAttributes; }
153 : };
154 : }
155 :
156 : //--------------------------------------------------------------------------
157 :
158 45709 : bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelData ) const
159 : {
160 : // We dont' actually want to talk to Fontconfig at all for symbol fonts
161 45709 : if( rFontSelData.IsSymbolFont() )
162 380 : return false;
163 : // StarSymbol is a unicode font, but it still deserves the symbol flag
164 89946 : if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
165 44617 : || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
166 11488 : return false;
167 :
168 : //see fdo#41556 and fdo#47636
169 : //fontconfig can return e.g. an italic font for a non-italic input and/or
170 : //different fonts depending on fontsize, bold, etc settings so don't cache
171 : //just on the name, cache map all the input and all the output not just map
172 : //from original selection to output fontname
173 33841 : FontSelectPatternAttributes& rPatternAttributes = rFontSelData;
174 33841 : CachedFontMapType &rCachedFontMap = const_cast<CachedFontMapType &>(maCachedFontMap);
175 33841 : CachedFontMapType::iterator itr = std::find_if(rCachedFontMap.begin(), rCachedFontMap.end(), equal(rPatternAttributes));
176 33841 : if (itr != rCachedFontMap.end())
177 : {
178 : // Cached substitution
179 31264 : rFontSelData.copyAttributes(itr->second);
180 31264 : if (itr != rCachedFontMap.begin())
181 : {
182 : // MRU, move it to the front
183 17099 : rCachedFontMap.splice(rCachedFontMap.begin(), rCachedFontMap, itr);
184 : }
185 31264 : return true;
186 : }
187 :
188 2577 : rtl::OUString aDummy;
189 2577 : const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, aDummy );
190 :
191 2577 : if( !aOut.maSearchName.Len() )
192 0 : return false;
193 :
194 2577 : const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
195 :
196 : #ifdef DEBUG
197 : const rtl::OString aOrigName(rtl::OUStringToOString(rFontSelData.maTargetName,
198 : RTL_TEXTENCODING_UTF8));
199 : const rtl::OString aSubstName(rtl::OUStringToOString(aOut.maSearchName,
200 : RTL_TEXTENCODING_UTF8));
201 : printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
202 : aOrigName.getStr(), rFontSelData.meWeight, rFontSelData.meItalic,
203 : rFontSelData.mePitch, rFontSelData.meWidthType );
204 : if( !bHaveSubstitute )
205 : printf( "no substitute available\n" );
206 : else
207 : printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.getStr(),
208 : aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
209 : #endif
210 :
211 2577 : if( bHaveSubstitute )
212 : {
213 2577 : rCachedFontMap.push_front(value_type(rFontSelData, aOut));
214 : //fairly arbitrary limit in this case, but I recall measuring max 8
215 : //fonts as the typical max amount of fonts in medium sized documents
216 2577 : if (rCachedFontMap.size() > 8)
217 2433 : rCachedFontMap.pop_back();
218 2577 : rFontSelData = aOut;
219 : }
220 :
221 2577 : return bHaveSubstitute;
222 : }
223 :
224 : // -----------------------------------------------------------------------
225 :
226 1275 : bool FcGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFontSelData,
227 : rtl::OUString& rMissingCodes ) const
228 : {
229 : // We dont' actually want to talk to Fontconfig at all for symbol fonts
230 1275 : if( rFontSelData.IsSymbolFont() )
231 0 : return false;
232 : // StarSymbol is a unicode font, but it still deserves the symbol flag
233 2550 : if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
234 1275 : || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
235 0 : return false;
236 :
237 1275 : const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
238 : // TODO: cache the unicode + srcfont specific result
239 : // FC doing it would be preferable because it knows the invariables
240 : // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
241 : // whereas we would have to check for every size or attribute
242 1275 : if( !aOut.maSearchName.Len() )
243 0 : return false;
244 :
245 1275 : const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
246 :
247 : #ifdef DEBUG
248 : const rtl::OString aOrigName(rtl::OUStringToOString(rFontSelData.maTargetName,
249 : RTL_TEXTENCODING_UTF8));
250 : const rtl::OString aSubstName(rtl::OUStringToOString(aOut.maSearchName,
251 : RTL_TEXTENCODING_UTF8));
252 : printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
253 : aOrigName.getStr(), rFontSelData.meWeight, rFontSelData.meItalic,
254 : rFontSelData.mePitch, rFontSelData.meWidthType );
255 : if( !bHaveSubstitute )
256 : printf( "no substitute available\n" );
257 : else
258 : printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.getStr(),
259 : aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
260 : #endif
261 :
262 1275 : if( bHaveSubstitute )
263 1275 : rFontSelData = aOut;
264 :
265 1275 : return bHaveSubstitute;
266 : }
267 :
268 : // ===========================================================================
269 :
270 :
271 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|