1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/font.cpp
3 // Purpose: wxFont for wxGTK
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling and Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
26 #include "wx/settings.h"
27 #include "wx/gdicmn.h"
30 #include "wx/fontutil.h"
31 #include "wx/tokenzr.h"
33 #include "wx/gtk/private.h"
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
39 // the default size (in points) for the fonts
40 static const int wxDEFAULT_FONT_SIZE
= 12;
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 class wxFontRefData
: public wxGDIRefData
49 // from broken down font parameters, also default ctor
50 wxFontRefData(int size
= -1,
51 wxFontFamily family
= wxFONTFAMILY_DEFAULT
,
52 wxFontStyle style
= wxFONTSTYLE_NORMAL
,
53 wxFontWeight weight
= wxFONTWEIGHT_NORMAL
,
54 bool underlined
= false,
55 bool strikethrough
= false,
56 const wxString
& faceName
= wxEmptyString
,
57 wxFontEncoding encoding
= wxFONTENCODING_DEFAULT
);
59 wxFontRefData(const wxString
& nativeFontInfoString
);
62 wxFontRefData( const wxFontRefData
& data
);
64 virtual ~wxFontRefData();
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
);
69 void SetFamily(wxFontFamily family
);
70 void SetStyle(wxFontStyle style
);
71 void SetWeight(wxFontWeight weight
);
72 void SetUnderlined(bool underlined
);
73 void SetStrikethrough(bool strikethrough
);
74 bool SetFaceName(const wxString
& facename
);
75 void SetEncoding(wxFontEncoding encoding
);
77 // and this one also modifies all the other font data fields
78 void SetNativeFontInfo(const wxNativeFontInfo
& info
);
81 // common part of all ctors
82 void Init(int pointSize
,
88 const wxString
& faceName
,
89 wxFontEncoding encoding
);
91 // set all fields from (already initialized and valid) m_nativeFontInfo
92 void InitFromNative();
95 // The native font info: basically a PangoFontDescription, plus
96 // 'underlined' and 'strikethrough' attributes not supported by Pango.
97 wxNativeFontInfo m_nativeFontInfo
;
102 #define M_FONTDATA ((wxFontRefData*)m_refData)
104 // ----------------------------------------------------------------------------
106 // ----------------------------------------------------------------------------
108 void wxFontRefData::Init(int pointSize
,
114 const wxString
& faceName
,
115 wxFontEncoding
WXUNUSED(encoding
))
117 if (family
== wxFONTFAMILY_DEFAULT
)
118 family
= wxFONTFAMILY_SWISS
;
120 // Create native font info
121 m_nativeFontInfo
.description
= pango_font_description_new();
123 // And set its values
124 if (!faceName
.empty())
126 pango_font_description_set_family( m_nativeFontInfo
.description
,
127 wxGTK_CONV_SYS(faceName
) );
134 SetStyle( style
== wxDEFAULT
? wxFONTSTYLE_NORMAL
: style
);
135 SetPointSize( (pointSize
== wxDEFAULT
|| pointSize
== -1)
136 ? wxDEFAULT_FONT_SIZE
138 SetWeight( weight
== wxDEFAULT
? wxFONTWEIGHT_NORMAL
: weight
);
139 SetUnderlined( underlined
);
140 SetStrikethrough( strikethrough
);
143 void wxFontRefData::InitFromNative()
146 PangoFontDescription
*desc
= m_nativeFontInfo
.description
;
148 // Pango sometimes needs to have a size
149 int pango_size
= pango_font_description_get_size( desc
);
151 m_nativeFontInfo
.SetPointSize(wxDEFAULT_FONT_SIZE
);
154 wxFontRefData::wxFontRefData( const wxFontRefData
& data
)
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());
163 wxFontRefData::wxFontRefData(int size
, wxFontFamily family
, wxFontStyle style
,
164 wxFontWeight weight
, bool underlined
, bool strikethrough
,
165 const wxString
& faceName
,
166 wxFontEncoding encoding
)
168 Init(size
, family
, style
, weight
, underlined
, strikethrough
, faceName
, encoding
);
171 wxFontRefData::wxFontRefData(const wxString
& nativeFontInfoString
)
173 m_nativeFontInfo
.FromString( nativeFontInfoString
);
178 wxFontRefData::~wxFontRefData()
182 // ----------------------------------------------------------------------------
183 // wxFontRefData SetXXX()
184 // ----------------------------------------------------------------------------
186 void wxFontRefData::SetPointSize(int pointSize
)
188 m_nativeFontInfo
.SetPointSize(pointSize
);
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).
199 bool wxFontRefData::SetPixelSize(const wxSize& pixelSize)
201 wxCHECK_MSG( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0, false,
202 "Negative values for the pixel size or zero pixel height are not allowed" );
204 if (wx_pango_version_check(1,8,0) != NULL ||
205 pixelSize.GetWidth() != 0)
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
213 pango_font_description_set_absolute_size( m_nativeFontInfo.description,
214 pixelSize.GetHeight() * PANGO_SCALE );
220 void wxFontRefData::SetFamily(wxFontFamily family
)
222 m_nativeFontInfo
.SetFamily(family
);
225 void wxFontRefData::SetStyle(wxFontStyle style
)
227 m_nativeFontInfo
.SetStyle(style
);
230 void wxFontRefData::SetWeight(wxFontWeight weight
)
232 m_nativeFontInfo
.SetWeight(weight
);
235 void wxFontRefData::SetUnderlined(bool underlined
)
237 m_nativeFontInfo
.SetUnderlined(underlined
);
240 void wxFontRefData::SetStrikethrough(bool strikethrough
)
242 m_nativeFontInfo
.SetStrikethrough(strikethrough
);
245 bool wxFontRefData::SetFaceName(const wxString
& facename
)
247 return m_nativeFontInfo
.SetFaceName(facename
);
250 void wxFontRefData::SetEncoding(wxFontEncoding
WXUNUSED(encoding
))
252 // with GTK+ 2 Pango always uses UTF8 internally, we cannot change it
255 void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo
& info
)
257 m_nativeFontInfo
= info
;
259 // set all the other font parameters from the native font info
263 // ----------------------------------------------------------------------------
265 // ----------------------------------------------------------------------------
267 wxFont::wxFont(const wxNativeFontInfo
& info
)
269 Create( info
.GetPointSize(),
273 info
.GetUnderlined(),
275 info
.GetEncoding() );
277 if ( info
.GetStrikethrough() )
278 SetStrikethrough(true);
281 wxFont::wxFont(const wxFontInfo
& info
)
283 m_refData
= new wxFontRefData(info
.GetPointSize(),
288 info
.IsStrikethrough(),
292 wxSize pixelSize
= info
.GetPixelSize();
293 if ( pixelSize
!= wxDefaultSize
)
294 SetPixelSize(pixelSize
);
297 bool wxFont::Create( int pointSize
,
302 const wxString
& face
,
303 wxFontEncoding encoding
)
307 m_refData
= new wxFontRefData(pointSize
, family
, style
, weight
,
308 underlined
, false, face
, encoding
);
313 bool wxFont::Create(const wxString
& fontname
)
315 // VZ: does this really happen?
316 if ( fontname
.empty() )
318 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
323 m_refData
= new wxFontRefData(fontname
);
332 // ----------------------------------------------------------------------------
334 // ----------------------------------------------------------------------------
336 int wxFont::GetPointSize() const
338 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
340 return M_FONTDATA
->m_nativeFontInfo
.GetPointSize();
343 wxString
wxFont::GetFaceName() const
345 wxCHECK_MSG( IsOk(), wxEmptyString
, wxT("invalid font") );
347 return M_FONTDATA
->m_nativeFontInfo
.GetFaceName();
350 wxFontFamily
wxFont::DoGetFamily() const
352 return M_FONTDATA
->m_nativeFontInfo
.GetFamily();
355 wxFontStyle
wxFont::GetStyle() const
357 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX
, wxT("invalid font") );
359 return M_FONTDATA
->m_nativeFontInfo
.GetStyle();
362 wxFontWeight
wxFont::GetWeight() const
364 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX
, wxT("invalid font") );
366 return M_FONTDATA
->m_nativeFontInfo
.GetWeight();
369 bool wxFont::GetUnderlined() const
371 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
373 return M_FONTDATA
->m_nativeFontInfo
.GetUnderlined();
376 bool wxFont::GetStrikethrough() const
378 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
380 return M_FONTDATA
->m_nativeFontInfo
.GetStrikethrough();
383 wxFontEncoding
wxFont::GetEncoding() const
385 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM
, wxT("invalid font") );
387 return wxFONTENCODING_UTF8
;
388 // Pango always uses UTF8... see also SetEncoding()
391 const wxNativeFontInfo
*wxFont::GetNativeFontInfo() const
393 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid font") );
395 return &(M_FONTDATA
->m_nativeFontInfo
);
398 bool wxFont::IsFixedWidth() const
400 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
402 return wxFontBase::IsFixedWidth();
405 // ----------------------------------------------------------------------------
406 // change font attributes
407 // ----------------------------------------------------------------------------
409 void wxFont::SetPointSize(int pointSize
)
413 M_FONTDATA
->SetPointSize(pointSize
);
416 void wxFont::SetFamily(wxFontFamily family
)
420 M_FONTDATA
->SetFamily(family
);
423 void wxFont::SetStyle(wxFontStyle style
)
427 M_FONTDATA
->SetStyle(style
);
430 void wxFont::SetWeight(wxFontWeight weight
)
434 M_FONTDATA
->SetWeight(weight
);
437 bool wxFont::SetFaceName(const wxString
& faceName
)
441 return M_FONTDATA
->SetFaceName(faceName
) &&
442 wxFontBase::SetFaceName(faceName
);
445 void wxFont::SetUnderlined(bool underlined
)
449 M_FONTDATA
->SetUnderlined(underlined
);
452 void wxFont::SetStrikethrough(bool strikethrough
)
456 M_FONTDATA
->SetStrikethrough(strikethrough
);
459 void wxFont::SetEncoding(wxFontEncoding encoding
)
463 M_FONTDATA
->SetEncoding(encoding
);
466 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo
& info
)
470 M_FONTDATA
->SetNativeFontInfo( info
);
473 wxGDIRefData
* wxFont::CreateGDIRefData() const
475 return new wxFontRefData
;
478 wxGDIRefData
* wxFont::CloneGDIRefData(const wxGDIRefData
* data
) const
480 return new wxFontRefData(*static_cast<const wxFontRefData
*>(data
));
483 bool wxFont::GTKSetPangoAttrs(PangoLayout
* layout
) const
485 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
488 PangoAttrList
* attrs
= pango_attr_list_new();
491 if (wx_pango_version_check(1,16,0))
493 // a PangoLayout which has leading/trailing spaces with underlined font
494 // is not correctly drawn by this pango version: Pango won't underline the spaces.
495 // This can be a problem; e.g. wxHTML rendering of underlined text relies on
496 // this behaviour. To workaround this problem, we use a special hack here
497 // suggested by pango maintainer Behdad Esfahbod: we prepend and append two
498 // empty space characters and give them a dummy colour attribute.
499 // This will force Pango to underline the leading/trailing spaces, too.
501 const char* text
= pango_layout_get_text(layout
);
502 const size_t n
= strlen(text
);
503 if ((n
> 0 && text
[0] == ' ') || (n
> 1 && text
[n
- 1] == ' '))
505 wxCharBuffer
buf(n
+ 6);
506 // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
507 memcpy(buf
.data(), "\342\200\214", 3);
508 // copy the user string
509 memcpy(buf
.data() + 3, text
, n
);
510 // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
511 memcpy(buf
.data() + 3 + n
, "\342\200\214", 3);
513 pango_layout_set_text(layout
, buf
, n
+ 6);
515 // Add dummy attributes (use colour as it's invisible anyhow for 0
516 // width spaces) to ensure that the spaces in the beginning/end of the
517 // string are underlined too.
518 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
521 pango_attr_list_insert(attrs
, a
);
523 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
524 a
->start_index
= n
+ 3;
525 a
->end_index
= n
+ 6;
526 pango_attr_list_insert(attrs
, a
);
531 a
= pango_attr_underline_new(PANGO_UNDERLINE_SINGLE
);
532 pango_attr_list_insert(attrs
, a
);
534 if (GetStrikethrough())
536 a
= pango_attr_strikethrough_new(true);
537 pango_attr_list_insert(attrs
, a
);
540 pango_layout_set_attributes(layout
, attrs
);
541 pango_attr_list_unref(attrs
);