rearrange some code in DoSetSize to facilitate upcoming changes
[wxWidgets.git] / src / gtk / font.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/font.cpp
3 // Purpose: wxFont for wxGTK
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling and Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #include "wx/font.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/log.h"
25 #include "wx/utils.h"
26 #include "wx/settings.h"
27 #include "wx/gdicmn.h"
28 #endif
29
30 #include "wx/fontutil.h"
31 #include "wx/tokenzr.h"
32
33 #include "wx/gtk/private.h"
34
35 // ----------------------------------------------------------------------------
36 // constants
37 // ----------------------------------------------------------------------------
38
39 // the default size (in points) for the fonts
40 static const int wxDEFAULT_FONT_SIZE = 12;
41
42 // ----------------------------------------------------------------------------
43 // wxFontRefData
44 // ----------------------------------------------------------------------------
45
46 class wxFontRefData : public wxGDIRefData
47 {
48 public:
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);
58
59 wxFontRefData(const wxString& nativeFontInfoString);
60
61 // copy ctor
62 wxFontRefData( const wxFontRefData& data );
63
64 virtual ~wxFontRefData();
65
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);
76
77 // and this one also modifies all the other font data fields
78 void SetNativeFontInfo(const wxNativeFontInfo& info);
79
80 protected:
81 // common part of all ctors
82 void Init(int pointSize,
83 wxFontFamily family,
84 wxFontStyle style,
85 wxFontWeight weight,
86 bool underlined,
87 bool strikethrough,
88 const wxString& faceName,
89 wxFontEncoding encoding);
90
91 // set all fields from (already initialized and valid) m_nativeFontInfo
92 void InitFromNative();
93
94 private:
95 bool m_underlined;
96 bool m_strikethrough;
97 // The native font info: basically a PangoFontDescription
98 wxNativeFontInfo m_nativeFontInfo;
99
100 friend class wxFont;
101 };
102
103 #define M_FONTDATA ((wxFontRefData*)m_refData)
104
105 // ----------------------------------------------------------------------------
106 // wxFontRefData
107 // ----------------------------------------------------------------------------
108
109 void wxFontRefData::Init(int pointSize,
110 wxFontFamily family,
111 wxFontStyle style,
112 wxFontWeight weight,
113 bool underlined,
114 bool strikethrough,
115 const wxString& faceName,
116 wxFontEncoding WXUNUSED(encoding))
117 {
118 if (family == wxFONTFAMILY_DEFAULT)
119 family = wxFONTFAMILY_SWISS;
120
121 m_underlined = underlined;
122 m_strikethrough = strikethrough;
123
124 // Create native font info
125 m_nativeFontInfo.description = pango_font_description_new();
126
127 // And set its values
128 if (!faceName.empty())
129 {
130 pango_font_description_set_family( m_nativeFontInfo.description,
131 wxGTK_CONV_SYS(faceName) );
132 }
133 else
134 {
135 SetFamily(family);
136 }
137
138 SetStyle( style == wxDEFAULT ? wxFONTSTYLE_NORMAL : style );
139 SetPointSize( (pointSize == wxDEFAULT || pointSize == -1)
140 ? wxDEFAULT_FONT_SIZE
141 : pointSize );
142 SetWeight( weight == wxDEFAULT ? wxFONTWEIGHT_NORMAL : weight );
143 }
144
145 void wxFontRefData::InitFromNative()
146 {
147 // Get native info
148 PangoFontDescription *desc = m_nativeFontInfo.description;
149
150 // Pango sometimes needs to have a size
151 int pango_size = pango_font_description_get_size( desc );
152 if (pango_size == 0)
153 m_nativeFontInfo.SetPointSize(wxDEFAULT_FONT_SIZE);
154
155 // Pango description are never underlined
156 m_underlined = false;
157 m_strikethrough = false;
158 }
159
160 wxFontRefData::wxFontRefData( const wxFontRefData& data )
161 : wxGDIRefData()
162 {
163 m_underlined = data.m_underlined;
164 m_strikethrough = data.m_strikethrough;
165
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());
170 }
171
172 wxFontRefData::wxFontRefData(int size, wxFontFamily family, wxFontStyle style,
173 wxFontWeight weight, bool underlined, bool strikethrough,
174 const wxString& faceName,
175 wxFontEncoding encoding)
176 {
177 Init(size, family, style, weight, underlined, strikethrough, faceName, encoding);
178 }
179
180 wxFontRefData::wxFontRefData(const wxString& nativeFontInfoString)
181 {
182 m_nativeFontInfo.FromString( nativeFontInfoString );
183
184 InitFromNative();
185 }
186
187 wxFontRefData::~wxFontRefData()
188 {
189 }
190
191 // ----------------------------------------------------------------------------
192 // wxFontRefData SetXXX()
193 // ----------------------------------------------------------------------------
194
195 void wxFontRefData::SetPointSize(int pointSize)
196 {
197 m_nativeFontInfo.SetPointSize(pointSize);
198 }
199
200 /*
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).
207
208 bool wxFontRefData::SetPixelSize(const wxSize& pixelSize)
209 {
210 wxCHECK_MSG( pixelSize.GetWidth() >= 0 && pixelSize.GetHeight() > 0, false,
211 "Negative values for the pixel size or zero pixel height are not allowed" );
212
213 if (wx_pango_version_check(1,8,0) != NULL ||
214 pixelSize.GetWidth() != 0)
215 {
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
219 return false;
220 }
221
222 pango_font_description_set_absolute_size( m_nativeFontInfo.description,
223 pixelSize.GetHeight() * PANGO_SCALE );
224
225 return true;
226 }
227 */
228
229 void wxFontRefData::SetFamily(wxFontFamily family)
230 {
231 m_nativeFontInfo.SetFamily(family);
232 }
233
234 void wxFontRefData::SetStyle(wxFontStyle style)
235 {
236 m_nativeFontInfo.SetStyle(style);
237 }
238
239 void wxFontRefData::SetWeight(wxFontWeight weight)
240 {
241 m_nativeFontInfo.SetWeight(weight);
242 }
243
244 void wxFontRefData::SetUnderlined(bool underlined)
245 {
246 m_underlined = underlined;
247
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
252 }
253
254 void wxFontRefData::SetStrikethrough(bool strikethrough)
255 {
256 m_strikethrough = strikethrough;
257 }
258
259 bool wxFontRefData::SetFaceName(const wxString& facename)
260 {
261 return m_nativeFontInfo.SetFaceName(facename);
262 }
263
264 void wxFontRefData::SetEncoding(wxFontEncoding WXUNUSED(encoding))
265 {
266 // with GTK+ 2 Pango always uses UTF8 internally, we cannot change it
267 }
268
269 void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo& info)
270 {
271 m_nativeFontInfo = info;
272
273 // set all the other font parameters from the native font info
274 InitFromNative();
275 }
276
277 // ----------------------------------------------------------------------------
278 // wxFont creation
279 // ----------------------------------------------------------------------------
280
281 wxFont::wxFont(const wxNativeFontInfo& info)
282 {
283 Create( info.GetPointSize(),
284 info.GetFamily(),
285 info.GetStyle(),
286 info.GetWeight(),
287 info.GetUnderlined(),
288 info.GetFaceName(),
289 info.GetEncoding() );
290 }
291
292 wxFont::wxFont(int pointSize,
293 wxFontFamily family,
294 int flags,
295 const wxString& face,
296 wxFontEncoding encoding)
297 {
298 m_refData = new wxFontRefData(pointSize, family,
299 GetStyleFromFlags(flags),
300 GetWeightFromFlags(flags),
301 GetUnderlinedFromFlags(flags),
302 false, face, encoding);
303 }
304
305 bool wxFont::Create( int pointSize,
306 wxFontFamily family,
307 wxFontStyle style,
308 wxFontWeight weight,
309 bool underlined,
310 const wxString& face,
311 wxFontEncoding encoding )
312 {
313 UnRef();
314
315 m_refData = new wxFontRefData(pointSize, family, style, weight,
316 underlined, false, face, encoding);
317
318 return true;
319 }
320
321 bool wxFont::Create(const wxString& fontname)
322 {
323 // VZ: does this really happen?
324 if ( fontname.empty() )
325 {
326 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
327
328 return true;
329 }
330
331 m_refData = new wxFontRefData(fontname);
332
333 return true;
334 }
335
336 wxFont::~wxFont()
337 {
338 }
339
340 // ----------------------------------------------------------------------------
341 // accessors
342 // ----------------------------------------------------------------------------
343
344 int wxFont::GetPointSize() const
345 {
346 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
347
348 return M_FONTDATA->m_nativeFontInfo.GetPointSize();
349 }
350
351 wxString wxFont::GetFaceName() const
352 {
353 wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
354
355 return M_FONTDATA->m_nativeFontInfo.GetFaceName();
356 }
357
358 wxFontFamily wxFont::DoGetFamily() const
359 {
360 return M_FONTDATA->m_nativeFontInfo.GetFamily();
361 }
362
363 wxFontStyle wxFont::GetStyle() const
364 {
365 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX, wxT("invalid font") );
366
367 return M_FONTDATA->m_nativeFontInfo.GetStyle();
368 }
369
370 wxFontWeight wxFont::GetWeight() const
371 {
372 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX, wxT("invalid font") );
373
374 return M_FONTDATA->m_nativeFontInfo.GetWeight();
375 }
376
377 bool wxFont::GetUnderlined() const
378 {
379 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
380
381 return M_FONTDATA->m_underlined;
382 }
383
384 bool wxFont::GetStrikethrough() const
385 {
386 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
387
388 return M_FONTDATA->m_strikethrough;
389 }
390
391 wxFontEncoding wxFont::GetEncoding() const
392 {
393 wxCHECK_MSG( IsOk(), wxFONTENCODING_SYSTEM, wxT("invalid font") );
394
395 return wxFONTENCODING_UTF8;
396 // Pango always uses UTF8... see also SetEncoding()
397 }
398
399 const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
400 {
401 wxCHECK_MSG( IsOk(), NULL, wxT("invalid font") );
402
403 return &(M_FONTDATA->m_nativeFontInfo);
404 }
405
406 bool wxFont::IsFixedWidth() const
407 {
408 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
409
410 return wxFontBase::IsFixedWidth();
411 }
412
413 // ----------------------------------------------------------------------------
414 // change font attributes
415 // ----------------------------------------------------------------------------
416
417 void wxFont::SetPointSize(int pointSize)
418 {
419 AllocExclusive();
420
421 M_FONTDATA->SetPointSize(pointSize);
422 }
423
424 void wxFont::SetFamily(wxFontFamily family)
425 {
426 AllocExclusive();
427
428 M_FONTDATA->SetFamily(family);
429 }
430
431 void wxFont::SetStyle(wxFontStyle style)
432 {
433 AllocExclusive();
434
435 M_FONTDATA->SetStyle(style);
436 }
437
438 void wxFont::SetWeight(wxFontWeight weight)
439 {
440 AllocExclusive();
441
442 M_FONTDATA->SetWeight(weight);
443 }
444
445 bool wxFont::SetFaceName(const wxString& faceName)
446 {
447 AllocExclusive();
448
449 return M_FONTDATA->SetFaceName(faceName) &&
450 wxFontBase::SetFaceName(faceName);
451 }
452
453 void wxFont::SetUnderlined(bool underlined)
454 {
455 AllocExclusive();
456
457 M_FONTDATA->SetUnderlined(underlined);
458 }
459
460 void wxFont::SetStrikethrough(bool strikethrough)
461 {
462 AllocExclusive();
463
464 M_FONTDATA->SetStrikethrough(strikethrough);
465 }
466
467 void wxFont::SetEncoding(wxFontEncoding encoding)
468 {
469 AllocExclusive();
470
471 M_FONTDATA->SetEncoding(encoding);
472 }
473
474 void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo& info )
475 {
476 AllocExclusive();
477
478 M_FONTDATA->SetNativeFontInfo( info );
479 }
480
481 wxGDIRefData* wxFont::CreateGDIRefData() const
482 {
483 return new wxFontRefData;
484 }
485
486 wxGDIRefData* wxFont::CloneGDIRefData(const wxGDIRefData* data) const
487 {
488 return new wxFontRefData(*static_cast<const wxFontRefData*>(data));
489 }
490
491 bool wxFont::GTKSetPangoAttrs(PangoLayout* layout) const
492 {
493 if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
494 return false;
495
496 PangoAttrList* attrs = pango_attr_list_new();
497 PangoAttribute* a;
498
499 if (wx_pango_version_check(1,16,0))
500 {
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.
508
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] == ' '))
512 {
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);
520
521 pango_layout_set_text(layout, buf, n + 6);
522
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);
527 a->start_index = 0;
528 a->end_index = 3;
529 pango_attr_list_insert(attrs, a);
530
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);
535 }
536 }
537 if (GetUnderlined())
538 {
539 a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
540 pango_attr_list_insert(attrs, a);
541 }
542 if (GetStrikethrough())
543 {
544 a = pango_attr_strikethrough_new(true);
545 pango_attr_list_insert(attrs, a);
546 }
547
548 pango_layout_set_attributes(layout, attrs);
549 pango_attr_list_unref(attrs);
550
551 return true;
552 }