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