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 /////////////////////////////////////////////////////////////////////////////
9 // ============================================================================
11 // ============================================================================
13 // ----------------------------------------------------------------------------
15 // ----------------------------------------------------------------------------
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
25 #include "wx/settings.h"
26 #include "wx/gdicmn.h"
29 #include "wx/fontutil.h"
30 #include "wx/tokenzr.h"
32 #include "wx/gtk/private.h"
34 // ----------------------------------------------------------------------------
36 // ----------------------------------------------------------------------------
38 // the default size (in points) for the fonts
39 static const int wxDEFAULT_FONT_SIZE
= 12;
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 class wxFontRefData
: public wxGDIRefData
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
);
58 wxFontRefData(const wxString
& nativeFontInfoString
);
61 wxFontRefData( const wxFontRefData
& data
);
63 virtual ~wxFontRefData();
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
);
76 // and this one also modifies all the other font data fields
77 void SetNativeFontInfo(const wxNativeFontInfo
& info
);
80 // common part of all ctors
81 void Init(int pointSize
,
87 const wxString
& faceName
,
88 wxFontEncoding encoding
);
90 // set all fields from (already initialized and valid) m_nativeFontInfo
91 void InitFromNative();
94 // The native font info: basically a PangoFontDescription, plus
95 // 'underlined' and 'strikethrough' attributes not supported by Pango.
96 wxNativeFontInfo m_nativeFontInfo
;
101 #define M_FONTDATA ((wxFontRefData*)m_refData)
103 // ----------------------------------------------------------------------------
105 // ----------------------------------------------------------------------------
107 void wxFontRefData::Init(int pointSize
,
113 const wxString
& faceName
,
114 wxFontEncoding
WXUNUSED(encoding
))
116 if (family
== wxFONTFAMILY_DEFAULT
)
117 family
= wxFONTFAMILY_SWISS
;
119 // Create native font info
120 m_nativeFontInfo
.description
= pango_font_description_new();
122 // And set its values
123 if (!faceName
.empty())
125 pango_font_description_set_family( m_nativeFontInfo
.description
,
126 wxGTK_CONV_SYS(faceName
) );
133 SetStyle( style
== wxDEFAULT
? wxFONTSTYLE_NORMAL
: style
);
134 SetPointSize( (pointSize
== wxDEFAULT
|| pointSize
== -1)
135 ? wxDEFAULT_FONT_SIZE
137 SetWeight( weight
== wxDEFAULT
? wxFONTWEIGHT_NORMAL
: weight
);
138 SetUnderlined( underlined
);
139 SetStrikethrough( strikethrough
);
142 void wxFontRefData::InitFromNative()
145 PangoFontDescription
*desc
= m_nativeFontInfo
.description
;
147 // Pango sometimes needs to have a size
148 int pango_size
= pango_font_description_get_size( desc
);
150 m_nativeFontInfo
.SetPointSize(wxDEFAULT_FONT_SIZE
);
153 wxFontRefData::wxFontRefData( const wxFontRefData
& data
)
156 // Forces a copy of the internal data. wxNativeFontInfo should probably
157 // have a copy ctor and assignment operator to fix this properly but that
158 // would break binary compatibility...
159 m_nativeFontInfo
.FromString(data
.m_nativeFontInfo
.ToString());
162 wxFontRefData::wxFontRefData(int size
, wxFontFamily family
, wxFontStyle style
,
163 wxFontWeight weight
, bool underlined
, bool strikethrough
,
164 const wxString
& faceName
,
165 wxFontEncoding encoding
)
167 Init(size
, family
, style
, weight
, underlined
, strikethrough
, faceName
, encoding
);
170 wxFontRefData::wxFontRefData(const wxString
& nativeFontInfoString
)
172 m_nativeFontInfo
.FromString( nativeFontInfoString
);
177 wxFontRefData::~wxFontRefData()
181 // ----------------------------------------------------------------------------
182 // wxFontRefData SetXXX()
183 // ----------------------------------------------------------------------------
185 void wxFontRefData::SetPointSize(int pointSize
)
187 m_nativeFontInfo
.SetPointSize(pointSize
);
191 NOTE: disabled because pango_font_description_set_absolute_size() and
192 wxDC::GetCharHeight() do not mix well: setting with the former a pixel
193 size of "30" makes the latter return 36...
194 Besides, we need to return GetPointSize() a point size value even if
195 SetPixelSize() was used and this would require further changes
196 (and use of pango_font_description_get_size_is_absolute in some places).
198 bool wxFontRefData::SetPixelSize(const wxSize& pixelSize)
200 wxCHECK_MSG( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0, false,
201 "Negative values for the pixel size or zero pixel height are not allowed" );
203 if (wx_pango_version_check(1,8,0) != NULL ||
204 pixelSize.GetWidth() != 0)
206 // NOTE: pango_font_description_set_absolute_size() only sets the font height;
207 // if the user set the pixel width of the font explicitly or the pango
208 // library is too old, we cannot proceed
212 pango_font_description_set_absolute_size( m_nativeFontInfo.description,
213 pixelSize.GetHeight() * PANGO_SCALE );
219 void wxFontRefData::SetFamily(wxFontFamily family
)
221 m_nativeFontInfo
.SetFamily(family
);
224 void wxFontRefData::SetStyle(wxFontStyle style
)
226 m_nativeFontInfo
.SetStyle(style
);
229 void wxFontRefData::SetWeight(wxFontWeight weight
)
231 m_nativeFontInfo
.SetWeight(weight
);
234 void wxFontRefData::SetUnderlined(bool underlined
)
236 m_nativeFontInfo
.SetUnderlined(underlined
);
239 void wxFontRefData::SetStrikethrough(bool strikethrough
)
241 m_nativeFontInfo
.SetStrikethrough(strikethrough
);
244 bool wxFontRefData::SetFaceName(const wxString
& facename
)
246 return m_nativeFontInfo
.SetFaceName(facename
);
249 void wxFontRefData::SetEncoding(wxFontEncoding
WXUNUSED(encoding
))
251 // with GTK+ 2 Pango always uses UTF8 internally, we cannot change it
254 void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo
& info
)
256 m_nativeFontInfo
= info
;
258 // set all the other font parameters from the native font info
262 // ----------------------------------------------------------------------------
264 // ----------------------------------------------------------------------------
266 wxFont::wxFont(const wxNativeFontInfo
& info
)
268 Create( info
.GetPointSize(),
272 info
.GetUnderlined(),
274 info
.GetEncoding() );
276 if ( info
.GetStrikethrough() )
277 SetStrikethrough(true);
280 wxFont::wxFont(const wxFontInfo
& info
)
282 m_refData
= new wxFontRefData(info
.GetPointSize(),
287 info
.IsStrikethrough(),
291 wxSize pixelSize
= info
.GetPixelSize();
292 if ( pixelSize
!= wxDefaultSize
)
293 SetPixelSize(pixelSize
);
296 bool wxFont::Create( int pointSize
,
301 const wxString
& face
,
302 wxFontEncoding encoding
)
306 m_refData
= new wxFontRefData(pointSize
, family
, style
, weight
,
307 underlined
, false, face
, encoding
);
312 bool wxFont::Create(const wxString
& fontname
)
314 // VZ: does this really happen?
315 if ( fontname
.empty() )
317 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
322 m_refData
= new wxFontRefData(fontname
);
331 // ----------------------------------------------------------------------------
333 // ----------------------------------------------------------------------------
335 int wxFont::GetPointSize() const
337 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
339 return M_FONTDATA
->m_nativeFontInfo
.GetPointSize();
342 wxString
wxFont::GetFaceName() const
344 wxCHECK_MSG( IsOk(), wxEmptyString
, wxT("invalid font") );
346 return M_FONTDATA
->m_nativeFontInfo
.GetFaceName();
349 wxFontFamily
wxFont::DoGetFamily() const
351 return M_FONTDATA
->m_nativeFontInfo
.GetFamily();
354 wxFontStyle
wxFont::GetStyle() const
356 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX
, wxT("invalid font") );
358 return M_FONTDATA
->m_nativeFontInfo
.GetStyle();
361 wxFontWeight
wxFont::GetWeight() const
363 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX
, wxT("invalid font") );
365 return M_FONTDATA
->m_nativeFontInfo
.GetWeight();
368 bool wxFont::GetUnderlined() const
370 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
372 return M_FONTDATA
->m_nativeFontInfo
.GetUnderlined();
375 bool wxFont::GetStrikethrough() const
377 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
379 return M_FONTDATA
->m_nativeFontInfo
.GetStrikethrough();
382 wxFontEncoding
wxFont::GetEncoding() const
384 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM
, wxT("invalid font") );
386 return wxFONTENCODING_UTF8
;
387 // Pango always uses UTF8... see also SetEncoding()
390 const wxNativeFontInfo
*wxFont::GetNativeFontInfo() const
392 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid font") );
394 return &(M_FONTDATA
->m_nativeFontInfo
);
397 bool wxFont::IsFixedWidth() const
399 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
401 return wxFontBase::IsFixedWidth();
404 // ----------------------------------------------------------------------------
405 // change font attributes
406 // ----------------------------------------------------------------------------
408 void wxFont::SetPointSize(int pointSize
)
412 M_FONTDATA
->SetPointSize(pointSize
);
415 void wxFont::SetFamily(wxFontFamily family
)
419 M_FONTDATA
->SetFamily(family
);
422 void wxFont::SetStyle(wxFontStyle style
)
426 M_FONTDATA
->SetStyle(style
);
429 void wxFont::SetWeight(wxFontWeight weight
)
433 M_FONTDATA
->SetWeight(weight
);
436 bool wxFont::SetFaceName(const wxString
& faceName
)
440 return M_FONTDATA
->SetFaceName(faceName
) &&
441 wxFontBase::SetFaceName(faceName
);
444 void wxFont::SetUnderlined(bool underlined
)
448 M_FONTDATA
->SetUnderlined(underlined
);
451 void wxFont::SetStrikethrough(bool strikethrough
)
455 M_FONTDATA
->SetStrikethrough(strikethrough
);
458 void wxFont::SetEncoding(wxFontEncoding encoding
)
462 M_FONTDATA
->SetEncoding(encoding
);
465 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo
& info
)
469 M_FONTDATA
->SetNativeFontInfo( info
);
472 wxGDIRefData
* wxFont::CreateGDIRefData() const
474 return new wxFontRefData
;
477 wxGDIRefData
* wxFont::CloneGDIRefData(const wxGDIRefData
* data
) const
479 return new wxFontRefData(*static_cast<const wxFontRefData
*>(data
));
482 bool wxFont::GTKSetPangoAttrs(PangoLayout
* layout
) const
484 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
487 PangoAttrList
* attrs
= pango_attr_list_new();
490 if (wx_pango_version_check(1,16,0))
492 // a PangoLayout which has leading/trailing spaces with underlined font
493 // is not correctly drawn by this pango version: Pango won't underline the spaces.
494 // This can be a problem; e.g. wxHTML rendering of underlined text relies on
495 // this behaviour. To workaround this problem, we use a special hack here
496 // suggested by pango maintainer Behdad Esfahbod: we prepend and append two
497 // empty space characters and give them a dummy colour attribute.
498 // This will force Pango to underline the leading/trailing spaces, too.
500 const char* text
= pango_layout_get_text(layout
);
501 const size_t n
= strlen(text
);
502 if ((n
> 0 && text
[0] == ' ') || (n
> 1 && text
[n
- 1] == ' '))
504 wxCharBuffer
buf(n
+ 6);
505 // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
506 memcpy(buf
.data(), "\342\200\214", 3);
507 // copy the user string
508 memcpy(buf
.data() + 3, text
, n
);
509 // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
510 memcpy(buf
.data() + 3 + n
, "\342\200\214", 3);
512 pango_layout_set_text(layout
, buf
, n
+ 6);
514 // Add dummy attributes (use colour as it's invisible anyhow for 0
515 // width spaces) to ensure that the spaces in the beginning/end of the
516 // string are underlined too.
517 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
520 pango_attr_list_insert(attrs
, a
);
522 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
523 a
->start_index
= n
+ 3;
524 a
->end_index
= n
+ 6;
525 pango_attr_list_insert(attrs
, a
);
530 a
= pango_attr_underline_new(PANGO_UNDERLINE_SINGLE
);
531 pango_attr_list_insert(attrs
, a
);
533 if (GetStrikethrough())
535 a
= pango_attr_strikethrough_new(true);
536 pango_attr_list_insert(attrs
, a
);
539 pango_layout_set_attributes(layout
, attrs
);
540 pango_attr_list_unref(attrs
);