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();
97 // The native font info: basically a PangoFontDescription
98 wxNativeFontInfo m_nativeFontInfo
;
103 #define M_FONTDATA ((wxFontRefData*)m_refData)
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 void wxFontRefData::Init(int pointSize
,
115 const wxString
& faceName
,
116 wxFontEncoding
WXUNUSED(encoding
))
118 if (family
== wxFONTFAMILY_DEFAULT
)
119 family
= wxFONTFAMILY_SWISS
;
121 m_underlined
= underlined
;
122 m_strikethrough
= strikethrough
;
124 // Create native font info
125 m_nativeFontInfo
.description
= pango_font_description_new();
127 // And set its values
128 if (!faceName
.empty())
130 pango_font_description_set_family( m_nativeFontInfo
.description
,
131 wxGTK_CONV_SYS(faceName
) );
138 SetStyle( style
== wxDEFAULT
? wxFONTSTYLE_NORMAL
: style
);
139 SetPointSize( (pointSize
== wxDEFAULT
|| pointSize
== -1)
140 ? wxDEFAULT_FONT_SIZE
142 SetWeight( weight
== wxDEFAULT
? wxFONTWEIGHT_NORMAL
: weight
);
145 void wxFontRefData::InitFromNative()
148 PangoFontDescription
*desc
= m_nativeFontInfo
.description
;
150 // Pango sometimes needs to have a size
151 int pango_size
= pango_font_description_get_size( desc
);
153 m_nativeFontInfo
.SetPointSize(wxDEFAULT_FONT_SIZE
);
155 // Pango description are never underlined
156 m_underlined
= false;
157 m_strikethrough
= false;
160 wxFontRefData::wxFontRefData( const wxFontRefData
& data
)
163 m_underlined
= data
.m_underlined
;
164 m_strikethrough
= data
.m_strikethrough
;
166 // Forces a copy of the internal data. wxNativeFontInfo should probably
167 // have a copy ctor and assignment operator to fix this properly but that
168 // would break binary compatibility...
169 m_nativeFontInfo
.FromString(data
.m_nativeFontInfo
.ToString());
172 wxFontRefData::wxFontRefData(int size
, wxFontFamily family
, wxFontStyle style
,
173 wxFontWeight weight
, bool underlined
, bool strikethrough
,
174 const wxString
& faceName
,
175 wxFontEncoding encoding
)
177 Init(size
, family
, style
, weight
, underlined
, strikethrough
, faceName
, encoding
);
180 wxFontRefData::wxFontRefData(const wxString
& nativeFontInfoString
)
182 m_nativeFontInfo
.FromString( nativeFontInfoString
);
187 wxFontRefData::~wxFontRefData()
191 // ----------------------------------------------------------------------------
192 // wxFontRefData SetXXX()
193 // ----------------------------------------------------------------------------
195 void wxFontRefData::SetPointSize(int pointSize
)
197 m_nativeFontInfo
.SetPointSize(pointSize
);
201 NOTE: disabled because pango_font_description_set_absolute_size() and
202 wxDC::GetCharHeight() do not mix well: setting with the former a pixel
203 size of "30" makes the latter return 36...
204 Besides, we need to return GetPointSize() a point size value even if
205 SetPixelSize() was used and this would require further changes
206 (and use of pango_font_description_get_size_is_absolute in some places).
208 bool wxFontRefData::SetPixelSize(const wxSize& pixelSize)
210 wxCHECK_MSG( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0, false,
211 "Negative values for the pixel size or zero pixel height are not allowed" );
213 if (wx_pango_version_check(1,8,0) != NULL ||
214 pixelSize.GetWidth() != 0)
216 // NOTE: pango_font_description_set_absolute_size() only sets the font height;
217 // if the user set the pixel width of the font explicitly or the pango
218 // library is too old, we cannot proceed
222 pango_font_description_set_absolute_size( m_nativeFontInfo.description,
223 pixelSize.GetHeight() * PANGO_SCALE );
229 void wxFontRefData::SetFamily(wxFontFamily family
)
231 m_nativeFontInfo
.SetFamily(family
);
234 void wxFontRefData::SetStyle(wxFontStyle style
)
236 m_nativeFontInfo
.SetStyle(style
);
239 void wxFontRefData::SetWeight(wxFontWeight weight
)
241 m_nativeFontInfo
.SetWeight(weight
);
244 void wxFontRefData::SetUnderlined(bool underlined
)
246 m_underlined
= underlined
;
248 // the Pango font descriptor does not have an underlined attribute
249 // (and wxNativeFontInfo::SetUnderlined asserts); rather it's
250 // wxWindowDCImpl::DoDrawText that handles underlined fonts, so we
251 // here we just need to save the underlined attribute
254 void wxFontRefData::SetStrikethrough(bool strikethrough
)
256 m_strikethrough
= strikethrough
;
259 bool wxFontRefData::SetFaceName(const wxString
& facename
)
261 return m_nativeFontInfo
.SetFaceName(facename
);
264 void wxFontRefData::SetEncoding(wxFontEncoding
WXUNUSED(encoding
))
266 // with GTK+ 2 Pango always uses UTF8 internally, we cannot change it
269 void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo
& info
)
271 m_nativeFontInfo
= info
;
273 // set all the other font parameters from the native font info
277 // ----------------------------------------------------------------------------
279 // ----------------------------------------------------------------------------
281 wxFont::wxFont(const wxNativeFontInfo
& info
)
283 Create( info
.GetPointSize(),
287 info
.GetUnderlined(),
289 info
.GetEncoding() );
292 wxFont::wxFont(int pointSize
,
295 const wxString
& face
,
296 wxFontEncoding encoding
)
298 m_refData
= new wxFontRefData(pointSize
, family
,
299 GetStyleFromFlags(flags
),
300 GetWeightFromFlags(flags
),
301 GetUnderlinedFromFlags(flags
),
302 false, face
, encoding
);
305 bool wxFont::Create( int pointSize
,
310 const wxString
& face
,
311 wxFontEncoding encoding
)
315 m_refData
= new wxFontRefData(pointSize
, family
, style
, weight
,
316 underlined
, false, face
, encoding
);
321 bool wxFont::Create(const wxString
& fontname
)
323 // VZ: does this really happen?
324 if ( fontname
.empty() )
326 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
331 m_refData
= new wxFontRefData(fontname
);
340 // ----------------------------------------------------------------------------
342 // ----------------------------------------------------------------------------
344 int wxFont::GetPointSize() const
346 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
348 return M_FONTDATA
->m_nativeFontInfo
.GetPointSize();
351 wxString
wxFont::GetFaceName() const
353 wxCHECK_MSG( IsOk(), wxEmptyString
, wxT("invalid font") );
355 return M_FONTDATA
->m_nativeFontInfo
.GetFaceName();
358 wxFontFamily
wxFont::DoGetFamily() const
360 return M_FONTDATA
->m_nativeFontInfo
.GetFamily();
363 wxFontStyle
wxFont::GetStyle() const
365 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX
, wxT("invalid font") );
367 return M_FONTDATA
->m_nativeFontInfo
.GetStyle();
370 wxFontWeight
wxFont::GetWeight() const
372 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX
, wxT("invalid font") );
374 return M_FONTDATA
->m_nativeFontInfo
.GetWeight();
377 bool wxFont::GetUnderlined() const
379 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
381 return M_FONTDATA
->m_underlined
;
384 bool wxFont::GetStrikethrough() const
386 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
388 return M_FONTDATA
->m_strikethrough
;
391 wxFontEncoding
wxFont::GetEncoding() const
393 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM
, wxT("invalid font") );
395 return wxFONTENCODING_UTF8
;
396 // Pango always uses UTF8... see also SetEncoding()
399 const wxNativeFontInfo
*wxFont::GetNativeFontInfo() const
401 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid font") );
403 return &(M_FONTDATA
->m_nativeFontInfo
);
406 bool wxFont::IsFixedWidth() const
408 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
410 return wxFontBase::IsFixedWidth();
413 // ----------------------------------------------------------------------------
414 // change font attributes
415 // ----------------------------------------------------------------------------
417 void wxFont::SetPointSize(int pointSize
)
421 M_FONTDATA
->SetPointSize(pointSize
);
424 void wxFont::SetFamily(wxFontFamily family
)
428 M_FONTDATA
->SetFamily(family
);
431 void wxFont::SetStyle(wxFontStyle style
)
435 M_FONTDATA
->SetStyle(style
);
438 void wxFont::SetWeight(wxFontWeight weight
)
442 M_FONTDATA
->SetWeight(weight
);
445 bool wxFont::SetFaceName(const wxString
& faceName
)
449 return M_FONTDATA
->SetFaceName(faceName
) &&
450 wxFontBase::SetFaceName(faceName
);
453 void wxFont::SetUnderlined(bool underlined
)
457 M_FONTDATA
->SetUnderlined(underlined
);
460 void wxFont::SetStrikethrough(bool strikethrough
)
464 M_FONTDATA
->SetStrikethrough(strikethrough
);
467 void wxFont::SetEncoding(wxFontEncoding encoding
)
471 M_FONTDATA
->SetEncoding(encoding
);
474 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo
& info
)
478 M_FONTDATA
->SetNativeFontInfo( info
);
481 wxGDIRefData
* wxFont::CreateGDIRefData() const
483 return new wxFontRefData
;
486 wxGDIRefData
* wxFont::CloneGDIRefData(const wxGDIRefData
* data
) const
488 return new wxFontRefData(*static_cast<const wxFontRefData
*>(data
));
491 bool wxFont::GTKSetPangoAttrs(PangoLayout
* layout
) const
493 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
496 PangoAttrList
* attrs
= pango_attr_list_new();
499 if (wx_pango_version_check(1,16,0))
501 // a PangoLayout which has leading/trailing spaces with underlined font
502 // is not correctly drawn by this pango version: Pango won't underline the spaces.
503 // This can be a problem; e.g. wxHTML rendering of underlined text relies on
504 // this behaviour. To workaround this problem, we use a special hack here
505 // suggested by pango maintainer Behdad Esfahbod: we prepend and append two
506 // empty space characters and give them a dummy colour attribute.
507 // This will force Pango to underline the leading/trailing spaces, too.
509 const char* text
= pango_layout_get_text(layout
);
510 const size_t n
= strlen(text
);
511 if ((n
> 0 && text
[0] == ' ') || (n
> 1 && text
[n
- 1] == ' '))
513 wxCharBuffer
buf(n
+ 6);
514 // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
515 memcpy(buf
.data(), "\342\200\214", 3);
516 // copy the user string
517 memcpy(buf
.data() + 3, text
, n
);
518 // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
519 memcpy(buf
.data() + 3 + n
, "\342\200\214", 3);
521 pango_layout_set_text(layout
, buf
, n
+ 6);
523 // Add dummy attributes (use colour as it's invisible anyhow for 0
524 // width spaces) to ensure that the spaces in the beginning/end of the
525 // string are underlined too.
526 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
529 pango_attr_list_insert(attrs
, a
);
531 a
= pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
532 a
->start_index
= n
+ 3;
533 a
->end_index
= n
+ 6;
534 pango_attr_list_insert(attrs
, a
);
539 a
= pango_attr_underline_new(PANGO_UNDERLINE_SINGLE
);
540 pango_attr_list_insert(attrs
, a
);
542 if (GetStrikethrough())
544 a
= pango_attr_strikethrough_new(true);
545 pango_attr_list_insert(attrs
, a
);
548 pango_layout_set_attributes(layout
, attrs
);
549 pango_attr_list_unref(attrs
);