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