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(int pointSize
,
284 const wxString
& face
,
285 wxFontEncoding encoding
)
287 m_refData
= new wxFontRefData(pointSize
, family
,
288 GetStyleFromFlags(flags
),
289 GetWeightFromFlags(flags
),
290 GetUnderlinedFromFlags(flags
),
291 GetStrikethroughFromFlags(flags
),
295 bool wxFont::Create( int pointSize
,
300 const wxString
& face
,
301 wxFontEncoding encoding
)
305 m_refData
= new wxFontRefData(pointSize
, family
, style
, weight
,
306 underlined
, false, face
, encoding
);
311 bool wxFont::Create(const wxString
& fontname
)
313 // VZ: does this really happen?
314 if ( fontname
.empty() )
316 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
321 m_refData
= new wxFontRefData(fontname
);
330 // ----------------------------------------------------------------------------
332 // ----------------------------------------------------------------------------
334 int wxFont::GetPointSize() const
336 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
338 return M_FONTDATA
->m_nativeFontInfo
.GetPointSize();
341 wxString
wxFont::GetFaceName() const
343 wxCHECK_MSG( IsOk(), wxEmptyString
, wxT("invalid font") );
345 return M_FONTDATA
->m_nativeFontInfo
.GetFaceName();
348 wxFontFamily
wxFont::DoGetFamily() const
350 return M_FONTDATA
->m_nativeFontInfo
.GetFamily();
353 wxFontStyle
wxFont::GetStyle() const
355 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX
, wxT("invalid font") );
357 return M_FONTDATA
->m_nativeFontInfo
.GetStyle();
360 wxFontWeight
wxFont::GetWeight() const
362 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX
, wxT("invalid font") );
364 return M_FONTDATA
->m_nativeFontInfo
.GetWeight();
367 bool wxFont::GetUnderlined() const
369 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
371 return M_FONTDATA
->m_nativeFontInfo
.GetUnderlined();
374 bool wxFont::GetStrikethrough() const
376 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
378 return M_FONTDATA
->m_nativeFontInfo
.GetStrikethrough();
381 wxFontEncoding
wxFont::GetEncoding() const
383 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM
, wxT("invalid font") );
385 return wxFONTENCODING_UTF8
;
386 // Pango always uses UTF8... see also SetEncoding()
389 const wxNativeFontInfo
*wxFont::GetNativeFontInfo() const
391 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid font") );
393 return &(M_FONTDATA
->m_nativeFontInfo
);
396 bool wxFont::IsFixedWidth() const
398 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
400 return wxFontBase::IsFixedWidth();
403 // ----------------------------------------------------------------------------
404 // change font attributes
405 // ----------------------------------------------------------------------------
407 void wxFont::SetPointSize(int pointSize
)
411 M_FONTDATA
->SetPointSize(pointSize
);
414 void wxFont::SetFamily(wxFontFamily family
)
418 M_FONTDATA
->SetFamily(family
);
421 void wxFont::SetStyle(wxFontStyle style
)
425 M_FONTDATA
->SetStyle(style
);
428 void wxFont::SetWeight(wxFontWeight weight
)
432 M_FONTDATA
->SetWeight(weight
);
435 bool wxFont::SetFaceName(const wxString
& faceName
)
439 return M_FONTDATA
->SetFaceName(faceName
) &&
440 wxFontBase::SetFaceName(faceName
);
443 void wxFont::SetUnderlined(bool underlined
)
447 M_FONTDATA
->SetUnderlined(underlined
);
450 void wxFont::SetStrikethrough(bool strikethrough
)
454 M_FONTDATA
->SetStrikethrough(strikethrough
);
457 void wxFont::SetEncoding(wxFontEncoding encoding
)
461 M_FONTDATA
->SetEncoding(encoding
);
464 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo
& info
)
468 M_FONTDATA
->SetNativeFontInfo( info
);
471 wxGDIRefData
* wxFont::CreateGDIRefData() const
473 return new wxFontRefData
;
476 wxGDIRefData
* wxFont::CloneGDIRefData(const wxGDIRefData
* data
) const
478 return new wxFontRefData(*static_cast<const wxFontRefData
*>(data
));
481 bool wxFont::GTKSetPangoAttrs(PangoLayout
* layout
) const
483 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
486 PangoAttrList
* attrs
= pango_attr_list_new();
489 if (wx_pango_version_check(1,16,0))
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.
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] == ' '))
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);
511 pango_layout_set_text(layout
, buf
, n
+ 6);
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.
516 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
519 pango_attr_list_insert(attrs
, a
);
521 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
522 a
->start_index
= n
+ 3;
523 a
->end_index
= n
+ 6;
524 pango_attr_list_insert(attrs
, a
);
529 a
= pango_attr_underline_new(PANGO_UNDERLINE_SINGLE
);
530 pango_attr_list_insert(attrs
, a
);
532 if (GetStrikethrough())
534 a
= pango_attr_strikethrough_new(true);
535 pango_attr_list_insert(attrs
, a
);
538 pango_layout_set_attributes(layout
, attrs
);
539 pango_attr_list_unref(attrs
);