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/log.h"
24 #include "wx/utils.h"
25 #include "wx/settings.h"
26 #include "wx/gdicmn.h"
27 #endif
28
29 #include "wx/fontutil.h"
30 #include "wx/tokenzr.h"
31
32 #include "wx/gtk/private.h"
33
34 // ----------------------------------------------------------------------------
35 // constants
36 // ----------------------------------------------------------------------------
37
38 // the default size (in points) for the fonts
39 static const int wxDEFAULT_FONT_SIZE = 12;
40
41 // ----------------------------------------------------------------------------
42 // wxFontRefData
43 // ----------------------------------------------------------------------------
44
45 class wxFontRefData : public wxGDIRefData
46 {
47 public:
48 // from broken down font parameters, also default ctor
49 wxFontRefData(int size = -1,
50 wxFontFamily family = wxFONTFAMILY_DEFAULT,
51 wxFontStyle style = wxFONTSTYLE_NORMAL,
52 wxFontWeight weight = wxFONTWEIGHT_NORMAL,
53 bool underlined = false,
54 bool strikethrough = false,
55 const wxString& faceName = wxEmptyString,
56 wxFontEncoding encoding = wxFONTENCODING_DEFAULT);
57
58 wxFontRefData(const wxString& nativeFontInfoString);
59
60 // copy ctor
61 wxFontRefData( const wxFontRefData& data );
62
63 virtual ~wxFontRefData();
64
65 // setters: all of them also take care to modify m_nativeFontInfo if we
66 // have it so as to not lose the information not carried by our fields
67 void SetPointSize(int pointSize);
68 void SetFamily(wxFontFamily family);
69 void SetStyle(wxFontStyle style);
70 void SetWeight(wxFontWeight weight);
71 void SetUnderlined(bool underlined);
72 void SetStrikethrough(bool strikethrough);
73 bool SetFaceName(const wxString& facename);
74 void SetEncoding(wxFontEncoding encoding);
75
76 // and this one also modifies all the other font data fields
77 void SetNativeFontInfo(const wxNativeFontInfo& info);
78
79 protected:
80 // common part of all ctors
81 void Init(int pointSize,
82 wxFontFamily family,
83 wxFontStyle style,
84 wxFontWeight weight,
85 bool underlined,
86 bool strikethrough,
87 const wxString& faceName,
88 wxFontEncoding encoding);
89
90 // set all fields from (already initialized and valid) m_nativeFontInfo
91 void InitFromNative();
92
93 private:
94 // The native font info: basically a PangoFontDescription, plus
95 // 'underlined' and 'strikethrough' attributes not supported by Pango.
96 wxNativeFontInfo m_nativeFontInfo;
97
98 friend class wxFont;
99 };
100
101 #define M_FONTDATA ((wxFontRefData*)m_refData)
102
103 // ----------------------------------------------------------------------------
104 // wxFontRefData
105 // ----------------------------------------------------------------------------
106
Init(int pointSize,wxFontFamily family,wxFontStyle style,wxFontWeight weight,bool underlined,bool strikethrough,const wxString & faceName,wxFontEncoding WXUNUSED (encoding))107 void wxFontRefData::Init(int pointSize,
108 wxFontFamily family,
109 wxFontStyle style,
110 wxFontWeight weight,
111 bool underlined,
112 bool strikethrough,
113 const wxString& faceName,
114 wxFontEncoding WXUNUSED(encoding))
115 {
116 if (family == wxFONTFAMILY_DEFAULT)
117 family = wxFONTFAMILY_SWISS;
118
119 // Create native font info
120 m_nativeFontInfo.description = pango_font_description_new();
121
122 // And set its values
123 if (!faceName.empty())
124 {
125 pango_font_description_set_family( m_nativeFontInfo.description,
126 wxGTK_CONV_SYS(faceName) );
127 }
128 else
129 {
130 SetFamily(family);
131 }
132
133 SetStyle( style == wxDEFAULT ? wxFONTSTYLE_NORMAL : style );
134 SetPointSize( (pointSize == wxDEFAULT || pointSize == -1)
135 ? wxDEFAULT_FONT_SIZE
136 : pointSize );
137 SetWeight( weight == wxDEFAULT ? wxFONTWEIGHT_NORMAL : weight );
138 SetUnderlined( underlined );
139 SetStrikethrough( strikethrough );
140 }
141
InitFromNative()142 void wxFontRefData::InitFromNative()
143 {
144 // Get native info
145 PangoFontDescription *desc = m_nativeFontInfo.description;
146
147 // Pango sometimes needs to have a size
148 int pango_size = pango_font_description_get_size( desc );
149 if (pango_size == 0)
150 m_nativeFontInfo.SetPointSize(wxDEFAULT_FONT_SIZE);
151 }
152
wxFontRefData(const wxFontRefData & data)153 wxFontRefData::wxFontRefData( const wxFontRefData& data )
154 : wxGDIRefData(),
155 m_nativeFontInfo(data.m_nativeFontInfo)
156 {
157 }
158
wxFontRefData(int size,wxFontFamily family,wxFontStyle style,wxFontWeight weight,bool underlined,bool strikethrough,const wxString & faceName,wxFontEncoding encoding)159 wxFontRefData::wxFontRefData(int size, wxFontFamily family, wxFontStyle style,
160 wxFontWeight weight, bool underlined, bool strikethrough,
161 const wxString& faceName,
162 wxFontEncoding encoding)
163 {
164 Init(size, family, style, weight, underlined, strikethrough, faceName, encoding);
165 }
166
wxFontRefData(const wxString & nativeFontInfoString)167 wxFontRefData::wxFontRefData(const wxString& nativeFontInfoString)
168 {
169 m_nativeFontInfo.FromString( nativeFontInfoString );
170
171 InitFromNative();
172 }
173
~wxFontRefData()174 wxFontRefData::~wxFontRefData()
175 {
176 }
177
178 // ----------------------------------------------------------------------------
179 // wxFontRefData SetXXX()
180 // ----------------------------------------------------------------------------
181
SetPointSize(int pointSize)182 void wxFontRefData::SetPointSize(int pointSize)
183 {
184 m_nativeFontInfo.SetPointSize(pointSize);
185 }
186
187 /*
188 NOTE: disabled because pango_font_description_set_absolute_size() and
189 wxDC::GetCharHeight() do not mix well: setting with the former a pixel
190 size of "30" makes the latter return 36...
191 Besides, we need to return GetPointSize() a point size value even if
192 SetPixelSize() was used and this would require further changes
193 (and use of pango_font_description_get_size_is_absolute in some places).
194
195 bool wxFontRefData::SetPixelSize(const wxSize& pixelSize)
196 {
197 wxCHECK_MSG( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0, false,
198 "Negative values for the pixel size or zero pixel height are not allowed" );
199
200 if (wx_pango_version_check(1,8,0) != NULL ||
201 pixelSize.GetWidth() != 0)
202 {
203 // NOTE: pango_font_description_set_absolute_size() only sets the font height;
204 // if the user set the pixel width of the font explicitly or the pango
205 // library is too old, we cannot proceed
206 return false;
207 }
208
209 pango_font_description_set_absolute_size( m_nativeFontInfo.description,
210 pixelSize.GetHeight() * PANGO_SCALE );
211
212 return true;
213 }
214 */
215
SetFamily(wxFontFamily family)216 void wxFontRefData::SetFamily(wxFontFamily family)
217 {
218 m_nativeFontInfo.SetFamily(family);
219 }
220
SetStyle(wxFontStyle style)221 void wxFontRefData::SetStyle(wxFontStyle style)
222 {
223 m_nativeFontInfo.SetStyle(style);
224 }
225
SetWeight(wxFontWeight weight)226 void wxFontRefData::SetWeight(wxFontWeight weight)
227 {
228 m_nativeFontInfo.SetWeight(weight);
229 }
230
SetUnderlined(bool underlined)231 void wxFontRefData::SetUnderlined(bool underlined)
232 {
233 m_nativeFontInfo.SetUnderlined(underlined);
234 }
235
SetStrikethrough(bool strikethrough)236 void wxFontRefData::SetStrikethrough(bool strikethrough)
237 {
238 m_nativeFontInfo.SetStrikethrough(strikethrough);
239 }
240
SetFaceName(const wxString & facename)241 bool wxFontRefData::SetFaceName(const wxString& facename)
242 {
243 return m_nativeFontInfo.SetFaceName(facename);
244 }
245
SetEncoding(wxFontEncoding WXUNUSED (encoding))246 void wxFontRefData::SetEncoding(wxFontEncoding WXUNUSED(encoding))
247 {
248 // with GTK+ 2 Pango always uses UTF8 internally, we cannot change it
249 }
250
SetNativeFontInfo(const wxNativeFontInfo & info)251 void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo& info)
252 {
253 m_nativeFontInfo = info;
254
255 // set all the other font parameters from the native font info
256 InitFromNative();
257 }
258
259 // ----------------------------------------------------------------------------
260 // wxFont creation
261 // ----------------------------------------------------------------------------
262
wxFont(const wxNativeFontInfo & info)263 wxFont::wxFont(const wxNativeFontInfo& info)
264 {
265 Create( info.GetPointSize(),
266 info.GetFamily(),
267 info.GetStyle(),
268 info.GetWeight(),
269 info.GetUnderlined(),
270 info.GetFaceName(),
271 info.GetEncoding() );
272
273 if ( info.GetStrikethrough() )
274 SetStrikethrough(true);
275 }
276
wxFont(const wxFontInfo & info)277 wxFont::wxFont(const wxFontInfo& info)
278 {
279 m_refData = new wxFontRefData(info.GetPointSize(),
280 info.GetFamily(),
281 info.GetStyle(),
282 info.GetWeight(),
283 info.IsUnderlined(),
284 info.IsStrikethrough(),
285 info.GetFaceName(),
286 info.GetEncoding());
287
288 wxSize pixelSize = info.GetPixelSize();
289 if ( pixelSize != wxDefaultSize )
290 SetPixelSize(pixelSize);
291 }
292
Create(int pointSize,wxFontFamily family,wxFontStyle style,wxFontWeight weight,bool underlined,const wxString & face,wxFontEncoding encoding)293 bool wxFont::Create( int pointSize,
294 wxFontFamily family,
295 wxFontStyle style,
296 wxFontWeight weight,
297 bool underlined,
298 const wxString& face,
299 wxFontEncoding encoding )
300 {
301 UnRef();
302
303 m_refData = new wxFontRefData(pointSize, family, style, weight,
304 underlined, false, face, encoding);
305
306 return true;
307 }
308
Create(const wxString & fontname)309 bool wxFont::Create(const wxString& fontname)
310 {
311 // VZ: does this really happen?
312 if ( fontname.empty() )
313 {
314 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
315
316 return true;
317 }
318
319 m_refData = new wxFontRefData(fontname);
320
321 return true;
322 }
323
~wxFont()324 wxFont::~wxFont()
325 {
326 }
327
328 // ----------------------------------------------------------------------------
329 // accessors
330 // ----------------------------------------------------------------------------
331
GetPointSize() const332 int wxFont::GetPointSize() const
333 {
334 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
335
336 return M_FONTDATA->m_nativeFontInfo.GetPointSize();
337 }
338
GetFaceName() const339 wxString wxFont::GetFaceName() const
340 {
341 wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
342
343 return M_FONTDATA->m_nativeFontInfo.GetFaceName();
344 }
345
DoGetFamily() const346 wxFontFamily wxFont::DoGetFamily() const
347 {
348 return M_FONTDATA->m_nativeFontInfo.GetFamily();
349 }
350
GetStyle() const351 wxFontStyle wxFont::GetStyle() const
352 {
353 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX, wxT("invalid font") );
354
355 return M_FONTDATA->m_nativeFontInfo.GetStyle();
356 }
357
GetWeight() const358 wxFontWeight wxFont::GetWeight() const
359 {
360 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX, wxT("invalid font") );
361
362 return M_FONTDATA->m_nativeFontInfo.GetWeight();
363 }
364
GetUnderlined() const365 bool wxFont::GetUnderlined() const
366 {
367 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
368
369 return M_FONTDATA->m_nativeFontInfo.GetUnderlined();
370 }
371
GetStrikethrough() const372 bool wxFont::GetStrikethrough() const
373 {
374 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
375
376 return M_FONTDATA->m_nativeFontInfo.GetStrikethrough();
377 }
378
GetEncoding() const379 wxFontEncoding wxFont::GetEncoding() const
380 {
381 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM, wxT("invalid font") );
382
383 return wxFONTENCODING_UTF8;
384 // Pango always uses UTF8... see also SetEncoding()
385 }
386
GetNativeFontInfo() const387 const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
388 {
389 wxCHECK_MSG( IsOk(), NULL, wxT("invalid font") );
390
391 return &(M_FONTDATA->m_nativeFontInfo);
392 }
393
IsFixedWidth() const394 bool wxFont::IsFixedWidth() const
395 {
396 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
397
398 return wxFontBase::IsFixedWidth();
399 }
400
401 // ----------------------------------------------------------------------------
402 // change font attributes
403 // ----------------------------------------------------------------------------
404
SetPointSize(int pointSize)405 void wxFont::SetPointSize(int pointSize)
406 {
407 AllocExclusive();
408
409 M_FONTDATA->SetPointSize(pointSize);
410 }
411
SetFamily(wxFontFamily family)412 void wxFont::SetFamily(wxFontFamily family)
413 {
414 AllocExclusive();
415
416 M_FONTDATA->SetFamily(family);
417 }
418
SetStyle(wxFontStyle style)419 void wxFont::SetStyle(wxFontStyle style)
420 {
421 AllocExclusive();
422
423 M_FONTDATA->SetStyle(style);
424 }
425
SetWeight(wxFontWeight weight)426 void wxFont::SetWeight(wxFontWeight weight)
427 {
428 AllocExclusive();
429
430 M_FONTDATA->SetWeight(weight);
431 }
432
SetFaceName(const wxString & faceName)433 bool wxFont::SetFaceName(const wxString& faceName)
434 {
435 AllocExclusive();
436
437 return M_FONTDATA->SetFaceName(faceName) &&
438 wxFontBase::SetFaceName(faceName);
439 }
440
SetUnderlined(bool underlined)441 void wxFont::SetUnderlined(bool underlined)
442 {
443 AllocExclusive();
444
445 M_FONTDATA->SetUnderlined(underlined);
446 }
447
SetStrikethrough(bool strikethrough)448 void wxFont::SetStrikethrough(bool strikethrough)
449 {
450 AllocExclusive();
451
452 M_FONTDATA->SetStrikethrough(strikethrough);
453 }
454
SetEncoding(wxFontEncoding encoding)455 void wxFont::SetEncoding(wxFontEncoding encoding)
456 {
457 AllocExclusive();
458
459 M_FONTDATA->SetEncoding(encoding);
460 }
461
DoSetNativeFontInfo(const wxNativeFontInfo & info)462 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo& info )
463 {
464 AllocExclusive();
465
466 M_FONTDATA->SetNativeFontInfo( info );
467 }
468
CreateGDIRefData() const469 wxGDIRefData* wxFont::CreateGDIRefData() const
470 {
471 return new wxFontRefData;
472 }
473
CloneGDIRefData(const wxGDIRefData * data) const474 wxGDIRefData* wxFont::CloneGDIRefData(const wxGDIRefData* data) const
475 {
476 return new wxFontRefData(*static_cast<const wxFontRefData*>(data));
477 }
478
GTKSetPangoAttrs(PangoLayout * layout) const479 bool wxFont::GTKSetPangoAttrs(PangoLayout* layout) const
480 {
481 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
482 return false;
483
484 PangoAttrList* attrs = pango_attr_list_new();
485 PangoAttribute* a;
486
487 #ifndef __WXGTK3__
488 if (wx_pango_version_check(1,16,0))
489 {
490 // a PangoLayout which has leading/trailing spaces with underlined font
491 // is not correctly drawn by this pango version: Pango won't underline the spaces.
492 // This can be a problem; e.g. wxHTML rendering of underlined text relies on
493 // this behaviour. To workaround this problem, we use a special hack here
494 // suggested by pango maintainer Behdad Esfahbod: we prepend and append two
495 // empty space characters and give them a dummy colour attribute.
496 // This will force Pango to underline the leading/trailing spaces, too.
497
498 const char* text = pango_layout_get_text(layout);
499 const size_t n = strlen(text);
500 if ((n > 0 && text[0] == ' ') || (n > 1 && text[n - 1] == ' '))
501 {
502 wxCharBuffer buf(n + 6);
503 // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
504 memcpy(buf.data(), "\342\200\214", 3);
505 // copy the user string
506 memcpy(buf.data() + 3, text, n);
507 // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
508 memcpy(buf.data() + 3 + n, "\342\200\214", 3);
509
510 pango_layout_set_text(layout, buf, n + 6);
511
512 // Add dummy attributes (use colour as it's invisible anyhow for 0
513 // width spaces) to ensure that the spaces in the beginning/end of the
514 // string are underlined too.
515 a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
516 a->start_index = 0;
517 a->end_index = 3;
518 pango_attr_list_insert(attrs, a);
519
520 a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
521 a->start_index = n + 3;
522 a->end_index = n + 6;
523 pango_attr_list_insert(attrs, a);
524 }
525 }
526 #endif // !__WXGTK3__
527
528 if (GetUnderlined())
529 {
530 a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
531 pango_attr_list_insert(attrs, a);
532 }
533 if (GetStrikethrough())
534 {
535 a = pango_attr_strikethrough_new(true);
536 pango_attr_list_insert(attrs, a);
537 }
538
539 pango_layout_set_attributes(layout, attrs);
540 pango_attr_list_unref(attrs);
541
542 return true;
543 }
544