1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/font.cpp
3 // Purpose: wxFont for wxGTK
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling and Julian Smart
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 // ============================================================================
10 // declarations
11 // ============================================================================
12
13 // ----------------------------------------------------------------------------
14 // headers
15 // ----------------------------------------------------------------------------
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #include "wx/font.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/intl.h"
24 #include "wx/log.h"
25 #include "wx/utils.h"
26 #include "wx/settings.h"
27 #include "wx/gdicmn.h"
28 #endif
29
30 #include "wx/fontutil.h"
31 #include "wx/tokenzr.h"
32
33 #include "wx/gtk/private.h"
34
35 // ----------------------------------------------------------------------------
36 // wxFontRefData
37 // ----------------------------------------------------------------------------
38
39 class wxFontRefData : public wxGDIRefData
40 {
41 public:
42 // main and also default ctor
43 wxFontRefData(const wxFontInfo& info = wxFontInfo());
44
45 wxFontRefData(const wxString& nativeFontInfoString);
46
47 // copy ctor
48 wxFontRefData( const wxFontRefData& data );
49
50 // setters: all of them also take care to modify m_nativeFontInfo if we
51 // have it so as to not lose the information not carried by our fields
52 void SetFractionalPointSize(double pointSize);
53 void SetFamily(wxFontFamily family);
54 void SetStyle(wxFontStyle style);
55 void SetWeight(wxFontWeight weight);
56 void SetNumericWeight(int weight);
57 void SetUnderlined(bool underlined);
58 void SetStrikethrough(bool strikethrough);
59 bool SetFaceName(const wxString& facename);
60 void SetEncoding(wxFontEncoding encoding);
61
62 // and this one also modifies all the other font data fields
63 void SetNativeFontInfo(const wxNativeFontInfo& info);
64
65 protected:
66 // set all fields from (already initialized and valid) m_nativeFontInfo
67 void InitFromNative();
68
69 private:
70 // The native font info: basically a PangoFontDescription, plus
71 // 'underlined' and 'strikethrough' attributes not supported by Pango.
72 wxNativeFontInfo m_nativeFontInfo;
73
74 friend class wxFont;
75 };
76
77 #define M_FONTDATA ((wxFontRefData*)m_refData)
78
79 // ----------------------------------------------------------------------------
80 // wxFontRefData
81 // ----------------------------------------------------------------------------
82
wxFontRefData(const wxFontInfo & info)83 wxFontRefData::wxFontRefData(const wxFontInfo& info)
84 {
85 // Create native font info
86 m_nativeFontInfo.description = pango_font_description_new();
87
88 // And set its values
89 if ( info.HasFaceName() )
90 {
91 pango_font_description_set_family( m_nativeFontInfo.description,
92 wxGTK_CONV_SYS(info.GetFaceName()) );
93 }
94 else
95 {
96 wxFontFamily family = info.GetFamily();
97 if (family == wxFONTFAMILY_DEFAULT)
98 family = wxFONTFAMILY_SWISS;
99 SetFamily(family);
100 }
101
102 SetStyle( info.GetStyle() );
103 m_nativeFontInfo.SetSizeOrDefault(info.GetFractionalPointSize());
104 SetNumericWeight( info.GetNumericWeight() );
105 SetUnderlined( info.IsUnderlined() );
106 SetStrikethrough( info.IsStrikethrough() );
107 }
108
InitFromNative()109 void wxFontRefData::InitFromNative()
110 {
111 // Get native info
112 PangoFontDescription *desc = m_nativeFontInfo.description;
113
114 // Pango sometimes needs to have a size
115 int pango_size = pango_font_description_get_size( desc );
116 if (pango_size == 0)
117 m_nativeFontInfo.SetSizeOrDefault(-1); // i.e. default
118 }
119
wxFontRefData(const wxFontRefData & data)120 wxFontRefData::wxFontRefData( const wxFontRefData& data )
121 : wxGDIRefData(),
122 m_nativeFontInfo(data.m_nativeFontInfo)
123 {
124 }
125
wxFontRefData(const wxString & nativeFontInfoString)126 wxFontRefData::wxFontRefData(const wxString& nativeFontInfoString)
127 {
128 m_nativeFontInfo.FromString( nativeFontInfoString );
129
130 InitFromNative();
131 }
132
133 // ----------------------------------------------------------------------------
134 // wxFontRefData SetXXX()
135 // ----------------------------------------------------------------------------
136
SetFractionalPointSize(double pointSize)137 void wxFontRefData::SetFractionalPointSize(double pointSize)
138 {
139 m_nativeFontInfo.SetFractionalPointSize(pointSize);
140 }
141
142 /*
143 NOTE: disabled because pango_font_description_set_absolute_size() and
144 wxDC::GetCharHeight() do not mix well: setting with the former a pixel
145 size of "30" makes the latter return 36...
146 Besides, we need to return GetPointSize() a point size value even if
147 SetPixelSize() was used and this would require further changes
148 (and use of pango_font_description_get_size_is_absolute in some places).
149
150 bool wxFontRefData::SetPixelSize(const wxSize& pixelSize)
151 {
152 wxCHECK_MSG( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0, false,
153 "Negative values for the pixel size or zero pixel height are not allowed" );
154
155 if (wx_pango_version_check(1,8,0) != NULL ||
156 pixelSize.GetWidth() != 0)
157 {
158 // NOTE: pango_font_description_set_absolute_size() only sets the font height;
159 // if the user set the pixel width of the font explicitly or the pango
160 // library is too old, we cannot proceed
161 return false;
162 }
163
164 pango_font_description_set_absolute_size( m_nativeFontInfo.description,
165 pixelSize.GetHeight() * PANGO_SCALE );
166
167 return true;
168 }
169 */
170
SetFamily(wxFontFamily family)171 void wxFontRefData::SetFamily(wxFontFamily family)
172 {
173 m_nativeFontInfo.SetFamily(family);
174 }
175
SetStyle(wxFontStyle style)176 void wxFontRefData::SetStyle(wxFontStyle style)
177 {
178 m_nativeFontInfo.SetStyle(style);
179 }
180
SetWeight(wxFontWeight weight)181 void wxFontRefData::SetWeight(wxFontWeight weight)
182 {
183 m_nativeFontInfo.SetWeight(weight);
184 }
185
SetNumericWeight(int weight)186 void wxFontRefData::SetNumericWeight(int weight)
187 {
188 m_nativeFontInfo.SetNumericWeight(weight);
189 }
190
SetUnderlined(bool underlined)191 void wxFontRefData::SetUnderlined(bool underlined)
192 {
193 m_nativeFontInfo.SetUnderlined(underlined);
194 }
195
SetStrikethrough(bool strikethrough)196 void wxFontRefData::SetStrikethrough(bool strikethrough)
197 {
198 m_nativeFontInfo.SetStrikethrough(strikethrough);
199 }
200
SetFaceName(const wxString & facename)201 bool wxFontRefData::SetFaceName(const wxString& facename)
202 {
203 return m_nativeFontInfo.SetFaceName(facename);
204 }
205
SetEncoding(wxFontEncoding WXUNUSED (encoding))206 void wxFontRefData::SetEncoding(wxFontEncoding WXUNUSED(encoding))
207 {
208 // with GTK+ 2 Pango always uses UTF8 internally, we cannot change it
209 }
210
SetNativeFontInfo(const wxNativeFontInfo & info)211 void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo& info)
212 {
213 m_nativeFontInfo = info;
214
215 // set all the other font parameters from the native font info
216 InitFromNative();
217 }
218
219 // ----------------------------------------------------------------------------
220 // wxFont creation
221 // ----------------------------------------------------------------------------
222
wxFont(const wxNativeFontInfo & info)223 wxFont::wxFont(const wxNativeFontInfo& info)
224 {
225 Create( info.GetPointSize(),
226 info.GetFamily(),
227 info.GetStyle(),
228 info.GetWeight(),
229 info.GetUnderlined(),
230 info.GetFaceName(),
231 info.GetEncoding() );
232
233 if ( info.GetStrikethrough() )
234 SetStrikethrough(true);
235 }
236
wxFont(const wxFontInfo & info)237 wxFont::wxFont(const wxFontInfo& info)
238 {
239 m_refData = new wxFontRefData(info);
240
241 wxSize pixelSize = info.GetPixelSize();
242 if ( pixelSize != wxDefaultSize )
243 SetPixelSize(pixelSize);
244 }
245
Create(int pointSize,wxFontFamily family,wxFontStyle style,wxFontWeight weight,bool underlined,const wxString & face,wxFontEncoding encoding)246 bool wxFont::Create( int pointSize,
247 wxFontFamily family,
248 wxFontStyle style,
249 wxFontWeight weight,
250 bool underlined,
251 const wxString& face,
252 wxFontEncoding encoding )
253 {
254 UnRef();
255
256 m_refData = new wxFontRefData(InfoFromLegacyParams(pointSize, family,
257 style, weight, underlined,
258 face, encoding));
259
260 return true;
261 }
262
Create(const wxString & fontname)263 bool wxFont::Create(const wxString& fontname)
264 {
265 // VZ: does this really happen?
266 if ( fontname.empty() )
267 {
268 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
269
270 return true;
271 }
272
273 m_refData = new wxFontRefData(fontname);
274
275 return true;
276 }
277
~wxFont()278 wxFont::~wxFont()
279 {
280 }
281
282 // ----------------------------------------------------------------------------
283 // accessors
284 // ----------------------------------------------------------------------------
285
GetFractionalPointSize() const286 double wxFont::GetFractionalPointSize() const
287 {
288 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
289
290 return M_FONTDATA->m_nativeFontInfo.GetFractionalPointSize();
291 }
292
GetFaceName() const293 wxString wxFont::GetFaceName() const
294 {
295 wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
296
297 return M_FONTDATA->m_nativeFontInfo.GetFaceName();
298 }
299
DoGetFamily() const300 wxFontFamily wxFont::DoGetFamily() const
301 {
302 return M_FONTDATA->m_nativeFontInfo.GetFamily();
303 }
304
GetStyle() const305 wxFontStyle wxFont::GetStyle() const
306 {
307 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX, wxT("invalid font") );
308
309 return M_FONTDATA->m_nativeFontInfo.GetStyle();
310 }
311
GetNumericWeight() const312 int wxFont::GetNumericWeight() const
313 {
314 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX, "invalid font" );
315
316 return M_FONTDATA->m_nativeFontInfo.GetNumericWeight();
317 }
318
GetUnderlined() const319 bool wxFont::GetUnderlined() const
320 {
321 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
322
323 return M_FONTDATA->m_nativeFontInfo.GetUnderlined();
324 }
325
GetStrikethrough() const326 bool wxFont::GetStrikethrough() const
327 {
328 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
329
330 return M_FONTDATA->m_nativeFontInfo.GetStrikethrough();
331 }
332
GetEncoding() const333 wxFontEncoding wxFont::GetEncoding() const
334 {
335 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM, wxT("invalid font") );
336
337 return wxFONTENCODING_UTF8;
338 // Pango always uses UTF8... see also SetEncoding()
339 }
340
GetNativeFontInfo() const341 const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
342 {
343 wxCHECK_MSG( IsOk(), NULL, wxT("invalid font") );
344
345 return &(M_FONTDATA->m_nativeFontInfo);
346 }
347
IsFixedWidth() const348 bool wxFont::IsFixedWidth() const
349 {
350 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
351
352 return wxFontBase::IsFixedWidth();
353 }
354
355 // ----------------------------------------------------------------------------
356 // change font attributes
357 // ----------------------------------------------------------------------------
358
SetFractionalPointSize(double pointSize)359 void wxFont::SetFractionalPointSize(double pointSize)
360 {
361 AllocExclusive();
362
363 M_FONTDATA->SetFractionalPointSize(pointSize);
364 }
365
SetFamily(wxFontFamily family)366 void wxFont::SetFamily(wxFontFamily family)
367 {
368 AllocExclusive();
369
370 M_FONTDATA->SetFamily(family);
371 }
372
SetStyle(wxFontStyle style)373 void wxFont::SetStyle(wxFontStyle style)
374 {
375 AllocExclusive();
376
377 M_FONTDATA->SetStyle(style);
378 }
379
SetNumericWeight(int weight)380 void wxFont::SetNumericWeight(int weight)
381 {
382 AllocExclusive();
383
384 M_FONTDATA->SetNumericWeight(weight);
385 }
386
SetFaceName(const wxString & faceName)387 bool wxFont::SetFaceName(const wxString& faceName)
388 {
389 AllocExclusive();
390
391 return M_FONTDATA->SetFaceName(faceName) &&
392 wxFontBase::SetFaceName(faceName);
393 }
394
SetUnderlined(bool underlined)395 void wxFont::SetUnderlined(bool underlined)
396 {
397 AllocExclusive();
398
399 M_FONTDATA->SetUnderlined(underlined);
400 }
401
SetStrikethrough(bool strikethrough)402 void wxFont::SetStrikethrough(bool strikethrough)
403 {
404 AllocExclusive();
405
406 M_FONTDATA->SetStrikethrough(strikethrough);
407 }
408
SetEncoding(wxFontEncoding encoding)409 void wxFont::SetEncoding(wxFontEncoding encoding)
410 {
411 AllocExclusive();
412
413 M_FONTDATA->SetEncoding(encoding);
414 }
415
DoSetNativeFontInfo(const wxNativeFontInfo & info)416 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo& info )
417 {
418 AllocExclusive();
419
420 M_FONTDATA->SetNativeFontInfo( info );
421 }
422
CreateGDIRefData() const423 wxGDIRefData* wxFont::CreateGDIRefData() const
424 {
425 return new wxFontRefData;
426 }
427
CloneGDIRefData(const wxGDIRefData * data) const428 wxGDIRefData* wxFont::CloneGDIRefData(const wxGDIRefData* data) const
429 {
430 return new wxFontRefData(*static_cast<const wxFontRefData*>(data));
431 }
432
GTKSetPangoAttrs(PangoLayout * layout) const433 bool wxFont::GTKSetPangoAttrs(PangoLayout* layout) const
434 {
435 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
436 return false;
437
438 PangoAttrList* attrs = pango_attr_list_new();
439 PangoAttribute* a;
440
441 #ifndef __WXGTK3__
442 if (wx_pango_version_check(1,16,0))
443 {
444 // a PangoLayout which has leading/trailing spaces with underlined font
445 // is not correctly drawn by this pango version: Pango won't underline the spaces.
446 // This can be a problem; e.g. wxHTML rendering of underlined text relies on
447 // this behaviour. To workaround this problem, we use a special hack here
448 // suggested by pango maintainer Behdad Esfahbod: we prepend and append two
449 // empty space characters and give them a dummy colour attribute.
450 // This will force Pango to underline the leading/trailing spaces, too.
451
452 const char* text = pango_layout_get_text(layout);
453 const size_t n = strlen(text);
454 if ((n > 0 && text[0] == ' ') || (n > 1 && text[n - 1] == ' '))
455 {
456 wxCharBuffer buf(n + 6);
457 // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
458 memcpy(buf.data(), "\342\200\214", 3);
459 // copy the user string
460 memcpy(buf.data() + 3, text, n);
461 // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
462 memcpy(buf.data() + 3 + n, "\342\200\214", 3);
463
464 pango_layout_set_text(layout, buf, n + 6);
465
466 // Add dummy attributes (use colour as it's invisible anyhow for 0
467 // width spaces) to ensure that the spaces in the beginning/end of the
468 // string are underlined too.
469 a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
470 a->start_index = 0;
471 a->end_index = 3;
472 pango_attr_list_insert(attrs, a);
473
474 a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
475 a->start_index = n + 3;
476 a->end_index = n + 6;
477 pango_attr_list_insert(attrs, a);
478 }
479 }
480 #endif // !__WXGTK3__
481
482 if (GetUnderlined())
483 {
484 a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
485 pango_attr_list_insert(attrs, a);
486 }
487 if (GetStrikethrough())
488 {
489 a = pango_attr_strikethrough_new(true);
490 pango_attr_list_insert(attrs, a);
491 }
492
493 pango_layout_set_attributes(layout, attrs);
494 pango_attr_list_unref(attrs);
495
496 return true;
497 }
498
499
500 // ----------------------------------------------------------------------------
501 // Support for adding private fonts
502 // ----------------------------------------------------------------------------
503
504 #if wxUSE_PRIVATE_FONTS
505
506 #include "wx/fontenum.h"
507 #include "wx/module.h"
508 #include "wx/gtk/private.h"
509 #include "wx/gtk/private/object.h"
510
511 #include <fontconfig/fontconfig.h>
512 #include <pango/pangofc-fontmap.h>
513
514 extern PangoContext* wxGetPangoContext();
515
516 namespace
517 {
518
519 FcConfig* gs_fcConfig = NULL;
520
521 // Module used to clean up the global FcConfig.
522 class wxFcConfigDestroyModule : public wxModule
523 {
524 public:
wxFcConfigDestroyModule()525 wxFcConfigDestroyModule() { }
526
OnInit()527 bool OnInit() wxOVERRIDE { return true; }
OnExit()528 void OnExit() wxOVERRIDE
529 {
530 if ( gs_fcConfig )
531 {
532 FcConfigDestroy(gs_fcConfig);
533 gs_fcConfig = NULL;
534 }
535 }
536
537 private:
538 wxDECLARE_DYNAMIC_CLASS(wxFcConfigDestroyModule);
539 };
540
541 wxIMPLEMENT_DYNAMIC_CLASS(wxFcConfigDestroyModule, wxModule);
542
543 } // anonymous namespace
544
AddPrivateFont(const wxString & filename)545 bool wxFontBase::AddPrivateFont(const wxString& filename)
546 {
547 // We already checked that we have the required functions at compile-time,
548 // but we should also check if they're available at run-time in case we use
549 // older versions of them than the ones we were compiled with.
550 if ( wx_pango_version_check(1,38,0) != NULL )
551 {
552 wxLogError(_("Using private fonts is not supported on this system: "
553 "Pango library is too old, 1.38 or later required."));
554 return false;
555 }
556
557 if ( !gs_fcConfig )
558 {
559 gs_fcConfig = FcInitLoadConfigAndFonts();
560 if ( !gs_fcConfig )
561 {
562 wxLogError(_("Failed to create font configuration object."));
563 return false;
564 }
565 }
566
567 if ( !FcConfigAppFontAddFile(gs_fcConfig,
568 reinterpret_cast<const FcChar8*>(
569 static_cast<const char*>(filename.utf8_str())
570 )) )
571 {
572 wxLogError(_("Failed to add custom font \"%s\"."), filename);
573 return false;
574 }
575
576 wxGtkObject<PangoContext> context(wxGetPangoContext());
577 PangoFontMap* const fmap = pango_context_get_font_map(context);
578 if ( !fmap || !PANGO_IS_FC_FONT_MAP(fmap) )
579 {
580 wxLogError(_("Failed to register font configuration using private fonts."));
581 return false;
582 }
583
584 PangoFcFontMap* const fcfmap = PANGO_FC_FONT_MAP(fmap);
585 pango_fc_font_map_set_config(fcfmap, gs_fcConfig);
586
587 // Ensure that the face names defined by private fonts are recognized by
588 // our SetFaceName() which uses wxFontEnumerator to check if the name is in
589 // the list of available faces.
590 wxFontEnumerator::InvalidateCache();
591
592 return true;
593 }
594
595 #endif // wxUSE_PRIVATE_FONTS
596
597