]> git.saurik.com Git - wxWidgets.git/blob - src/motif/font.cpp
preserve type when loaded image is rescaled, #11543
[wxWidgets.git] / src / motif / font.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/font.cpp
3 // Purpose: wxFont class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __VMS
24 #pragma message disable nosimpint
25 #include "wx/vms_x_fix.h"
26 #endif
27 #include <Xm/Xm.h>
28 #ifdef __VMS
29 #pragma message enable nosimpint
30 #endif
31
32 #include "wx/font.h"
33
34 #ifndef WX_PRECOMP
35 #include "wx/string.h"
36 #include "wx/utils.h" // for wxGetDisplay()
37 #include "wx/settings.h"
38 #include "wx/gdicmn.h"
39 #endif
40
41 #include "wx/fontutil.h" // for wxNativeFontInfo
42 #include "wx/tokenzr.h"
43 #include "wx/motif/private.h"
44
45 IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject)
46
47 // ----------------------------------------------------------------------------
48 // private classes
49 // ----------------------------------------------------------------------------
50
51 // For every wxFont, there must be a font for each display and scale requested.
52 // So these objects are stored in wxFontRefData::m_fonts
53 class wxXFont : public wxObject
54 {
55 public:
56 wxXFont();
57 virtual ~wxXFont();
58
59 #if !wxMOTIF_NEW_FONT_HANDLING
60 WXFontStructPtr m_fontStruct; // XFontStruct
61 #endif
62 #if !wxMOTIF_USE_RENDER_TABLE
63 WXFontList m_fontList; // Motif XmFontList
64 #else // if wxMOTIF_USE_RENDER_TABLE
65 WXRenderTable m_renderTable; // Motif XmRenderTable
66 WXRendition m_rendition; // Motif XmRendition
67 #endif
68 WXDisplay* m_display; // XDisplay
69 int m_scale; // Scale * 100
70 };
71
72 class wxFontRefData: public wxGDIRefData
73 {
74 friend class wxFont;
75
76 public:
77 wxFontRefData(int size = wxDEFAULT,
78 wxFontFamily family = wxFONTFAMILY_DEFAULT,
79 wxFontStyle style = wxFONTSTYLE_NORMAL,
80 wxFontWeight weight = wxFONTWEIGHT_NORMAL,
81 bool underlined = false,
82 const wxString& faceName = wxEmptyString,
83 wxFontEncoding encoding = wxFONTENCODING_DEFAULT)
84 {
85 Init(size, family, style, weight, underlined, faceName, encoding);
86 }
87
88 wxFontRefData(const wxFontRefData& data)
89 {
90 Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight,
91 data.m_underlined, data.m_faceName, data.m_encoding);
92 }
93
94 virtual ~wxFontRefData();
95
96 protected:
97 // common part of all ctors
98 void Init(int size,
99 wxFontFamily family,
100 wxFontStyle style,
101 wxFontWeight weight,
102 bool underlined,
103 const wxString& faceName,
104 wxFontEncoding encoding);
105
106 // font attributes
107 int m_pointSize;
108 wxFontFamily m_family;
109 wxFontStyle m_style;
110 wxFontWeight m_weight;
111 bool m_underlined;
112 wxString m_faceName;
113 wxFontEncoding m_encoding;
114
115 wxNativeFontInfo m_nativeFontInfo;
116
117 // A list of wxXFonts
118 wxList m_fonts;
119 };
120
121 // ============================================================================
122 // implementation
123 // ============================================================================
124
125 // ----------------------------------------------------------------------------
126 // wxXFont
127 // ----------------------------------------------------------------------------
128
129 wxXFont::wxXFont()
130 {
131 #if !wxMOTIF_NEW_FONT_HANDLING
132 m_fontStruct = (WXFontStructPtr) 0;
133 #endif
134 #if !wxMOTIF_USE_RENDER_TABLE
135 m_fontList = (WXFontList) 0;
136 #else // if wxMOTIF_USE_RENDER_TABLE
137 m_renderTable = (WXRenderTable) 0;
138 m_rendition = (WXRendition) 0;
139 #endif
140 m_display = (WXDisplay*) 0;
141 m_scale = 100;
142 }
143
144 wxXFont::~wxXFont()
145 {
146 #if !wxMOTIF_USE_RENDER_TABLE
147 if (m_fontList)
148 XmFontListFree ((XmFontList) m_fontList);
149 m_fontList = NULL;
150 #else // if wxMOTIF_USE_RENDER_TABLE
151 if (m_renderTable)
152 XmRenderTableFree ((XmRenderTable) m_renderTable);
153 m_renderTable = NULL;
154 #endif
155
156 // TODO: why does freeing the font produce a segv???
157 // Note that XFreeFont wasn't called in wxWin 1.68 either.
158 // MBN: probably some interaction with fonts being still
159 // in use in some widgets...
160 // XFontStruct* fontStruct = (XFontStruct*) m_fontStruct;
161 // XFreeFont((Display*) m_display, fontStruct);
162 }
163
164 // ----------------------------------------------------------------------------
165 // wxFontRefData
166 // ----------------------------------------------------------------------------
167
168 void wxFontRefData::Init(int pointSize,
169 wxFontFamily family,
170 wxFontStyle style,
171 wxFontWeight weight,
172 bool underlined,
173 const wxString& faceName,
174 wxFontEncoding encoding)
175 {
176 if (family == wxDEFAULT)
177 m_family = wxFONTFAMILY_SWISS;
178 else
179 m_family = family;
180
181 m_faceName = faceName;
182
183 if (style == wxDEFAULT)
184 m_style = wxFONTSTYLE_NORMAL;
185 else
186 m_style = style;
187
188 if (weight == wxDEFAULT)
189 m_weight = wxFONTWEIGHT_NORMAL;
190 else
191 m_weight = weight;
192
193 if (pointSize == wxDEFAULT)
194 m_pointSize = 12;
195 else
196 m_pointSize = pointSize;
197
198 m_underlined = underlined;
199 m_encoding = encoding;
200 }
201
202 wxFontRefData::~wxFontRefData()
203 {
204 wxList::compatibility_iterator node = m_fonts.GetFirst();
205 while (node)
206 {
207 wxXFont* f = (wxXFont*) node->GetData();
208 delete f;
209 node = node->GetNext();
210 }
211 m_fonts.Clear();
212 }
213
214 #define M_FONTDATA ((wxFontRefData*)m_refData)
215
216 // ----------------------------------------------------------------------------
217 // wxFont
218 // ----------------------------------------------------------------------------
219
220 wxFont::wxFont(const wxNativeFontInfo& info)
221 {
222 (void)Create(info.GetXFontName());
223 }
224
225 bool wxFont::Create(int pointSize,
226 wxFontFamily family,
227 wxFontStyle style,
228 wxFontWeight weight,
229 bool underlined,
230 const wxString& faceName,
231 wxFontEncoding encoding)
232 {
233 UnRef();
234 m_refData = new wxFontRefData(pointSize, family, style, weight,
235 underlined, faceName, encoding);
236
237 return true;
238 }
239
240 bool wxFont::Create(const wxString& fontname, wxFontEncoding enc)
241 {
242 if( !fontname )
243 {
244 *this = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT);
245 return true;
246 }
247
248 m_refData = new wxFontRefData();
249
250 M_FONTDATA->m_nativeFontInfo.SetXFontName(fontname); // X font name
251
252 wxString tmp;
253
254 wxStringTokenizer tn( fontname, wxT("-") );
255
256 tn.GetNextToken(); // skip initial empty token
257 tn.GetNextToken(); // foundry
258
259
260 M_FONTDATA->m_faceName = tn.GetNextToken(); // family
261
262 tmp = tn.GetNextToken().MakeUpper(); // weight
263 if (tmp == wxT("BOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
264 if (tmp == wxT("BLACK")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
265 if (tmp == wxT("EXTRABOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
266 if (tmp == wxT("DEMIBOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
267 if (tmp == wxT("ULTRABOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
268
269 if (tmp == wxT("LIGHT")) M_FONTDATA->m_weight = wxFONTWEIGHT_LIGHT;
270 if (tmp == wxT("THIN")) M_FONTDATA->m_weight = wxFONTWEIGHT_LIGHT;
271
272 tmp = tn.GetNextToken().MakeUpper(); // slant
273 if (tmp == wxT("I")) M_FONTDATA->m_style = wxFONTSTYLE_ITALIC;
274 if (tmp == wxT("O")) M_FONTDATA->m_style = wxFONTSTYLE_ITALIC;
275
276 tn.GetNextToken(); // set width
277 tn.GetNextToken(); // add. style
278 tn.GetNextToken(); // pixel size
279
280 tmp = tn.GetNextToken(); // pointsize
281 if (tmp != wxT("*"))
282 {
283 long num = wxStrtol (tmp.mb_str(), (wxChar **) NULL, 10);
284 M_FONTDATA->m_pointSize = (int)(num / 10);
285 }
286
287 tn.GetNextToken(); // x-res
288 tn.GetNextToken(); // y-res
289
290 tmp = tn.GetNextToken().MakeUpper(); // spacing
291
292 if (tmp == wxT("M"))
293 M_FONTDATA->m_family = wxFONTFAMILY_MODERN;
294 else if (M_FONTDATA->m_faceName == wxT("TIMES"))
295 M_FONTDATA->m_family = wxFONTFAMILY_ROMAN;
296 else if (M_FONTDATA->m_faceName == wxT("HELVETICA"))
297 M_FONTDATA->m_family = wxFONTFAMILY_SWISS;
298 else if (M_FONTDATA->m_faceName == wxT("LUCIDATYPEWRITER"))
299 M_FONTDATA->m_family = wxFONTFAMILY_TELETYPE;
300 else if (M_FONTDATA->m_faceName == wxT("LUCIDA"))
301 M_FONTDATA->m_family = wxFONTFAMILY_DECORATIVE;
302 else if (M_FONTDATA->m_faceName == wxT("UTOPIA"))
303 M_FONTDATA->m_family = wxFONTFAMILY_SCRIPT;
304
305 tn.GetNextToken(); // avg width
306
307 // deal with font encoding
308 M_FONTDATA->m_encoding = enc;
309 if ( M_FONTDATA->m_encoding == wxFONTENCODING_SYSTEM )
310 {
311 wxString registry = tn.GetNextToken().MakeUpper(),
312 encoding = tn.GetNextToken().MakeUpper();
313
314 if ( registry == wxT("ISO8859") )
315 {
316 int cp;
317 if ( wxSscanf(encoding, wxT("%d"), &cp) == 1 )
318 {
319 M_FONTDATA->m_encoding =
320 (wxFontEncoding)(wxFONTENCODING_ISO8859_1 + cp - 1);
321 }
322 }
323 else if ( registry == wxT("MICROSOFT") )
324 {
325 int cp;
326 if ( wxSscanf(encoding, wxT("cp125%d"), &cp) == 1 )
327 {
328 M_FONTDATA->m_encoding =
329 (wxFontEncoding)(wxFONTENCODING_CP1250 + cp);
330 }
331 }
332 else if ( registry == wxT("KOI8") )
333 {
334 M_FONTDATA->m_encoding = wxFONTENCODING_KOI8;
335 }
336 //else: unknown encoding - may be give a warning here?
337 else
338 return false;
339 }
340 return true;
341 }
342
343 wxFont::~wxFont()
344 {
345 }
346
347 wxGDIRefData *wxFont::CreateGDIRefData() const
348 {
349 return new wxFontRefData;
350 }
351
352 wxGDIRefData *wxFont::CloneGDIRefData(const wxGDIRefData *data) const
353 {
354 return new wxFontRefData(*static_cast<const wxFontRefData *>(data));
355 }
356
357 // ----------------------------------------------------------------------------
358 // change the font attributes
359 // ----------------------------------------------------------------------------
360
361 void wxFont::Unshare()
362 {
363 // Don't change shared data
364 if (!m_refData)
365 {
366 m_refData = new wxFontRefData();
367 }
368 else
369 {
370 wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData);
371 UnRef();
372 m_refData = ref;
373 }
374 }
375
376 void wxFont::SetPointSize(int pointSize)
377 {
378 Unshare();
379
380 M_FONTDATA->m_pointSize = pointSize;
381 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
382 }
383
384 void wxFont::SetFamily(wxFontFamily family)
385 {
386 Unshare();
387
388 M_FONTDATA->m_family = family;
389 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
390 }
391
392 void wxFont::SetStyle(wxFontStyle style)
393 {
394 Unshare();
395
396 M_FONTDATA->m_style = style;
397 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
398 }
399
400 void wxFont::SetWeight(wxFontWeight weight)
401 {
402 Unshare();
403
404 M_FONTDATA->m_weight = weight;
405 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
406 }
407
408 bool wxFont::SetFaceName(const wxString& faceName)
409 {
410 Unshare();
411
412 M_FONTDATA->m_faceName = faceName;
413 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
414
415 return wxFontBase::SetFaceName(faceName);
416 }
417
418 void wxFont::SetUnderlined(bool underlined)
419 {
420 Unshare();
421
422 M_FONTDATA->m_underlined = underlined;
423 }
424
425 void wxFont::SetEncoding(wxFontEncoding encoding)
426 {
427 Unshare();
428
429 M_FONTDATA->m_encoding = encoding;
430 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
431 }
432
433 void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info)
434 {
435 Unshare();
436
437 M_FONTDATA->m_nativeFontInfo = info;
438 }
439
440 // ----------------------------------------------------------------------------
441 // query font attributes
442 // ----------------------------------------------------------------------------
443
444 int wxFont::GetPointSize() const
445 {
446 wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
447
448 return M_FONTDATA->m_pointSize;
449 }
450
451 wxString wxFont::GetFaceName() const
452 {
453 wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid font") );
454
455 return M_FONTDATA->m_faceName ;
456 }
457
458 wxFontFamily wxFont::GetFamily() const
459 {
460 wxCHECK_MSG( Ok(), wxFONTFAMILY_MAX, wxT("invalid font") );
461
462 return M_FONTDATA->m_family;
463 }
464
465 wxFontStyle wxFont::GetStyle() const
466 {
467 wxCHECK_MSG( Ok(), wxFONTSTYLE_MAX, wxT("invalid font") );
468
469 return M_FONTDATA->m_style;
470 }
471
472 wxFontWeight wxFont::GetWeight() const
473 {
474 wxCHECK_MSG( Ok(), wxFONTWEIGHT_MAX, wxT("invalid font") );
475
476 return M_FONTDATA->m_weight;
477 }
478
479 bool wxFont::GetUnderlined() const
480 {
481 wxCHECK_MSG( Ok(), false, wxT("invalid font") );
482
483 return M_FONTDATA->m_underlined;
484 }
485
486 wxFontEncoding wxFont::GetEncoding() const
487 {
488 wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, wxT("invalid font") );
489
490 return M_FONTDATA->m_encoding;
491 }
492
493 const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
494 {
495 wxCHECK_MSG( Ok(), NULL, wxT("invalid font") );
496
497 if(M_FONTDATA->m_nativeFontInfo.GetXFontName().empty())
498 GetInternalFont();
499
500 return &(M_FONTDATA->m_nativeFontInfo);
501 }
502
503 // ----------------------------------------------------------------------------
504 // real implementation
505 // ----------------------------------------------------------------------------
506
507 // Find an existing, or create a new, XFontStruct
508 // based on this wxFont and the given scale. Append the
509 // font to list in the private data for future reference.
510 wxXFont* wxFont::GetInternalFont(double scale, WXDisplay* display) const
511 {
512 if ( !Ok() )
513 return NULL;
514
515 long intScale = long(scale * 100.0 + 0.5); // key for wxXFont
516 int pointSize = (M_FONTDATA->m_pointSize * 10 * intScale) / 100;
517
518 // search existing fonts first
519 wxList::compatibility_iterator node = M_FONTDATA->m_fonts.GetFirst();
520 while (node)
521 {
522 wxXFont* f = (wxXFont*) node->GetData();
523 if ((!display || (f->m_display == display)) && (f->m_scale == intScale))
524 return f;
525 node = node->GetNext();
526 }
527
528 // not found, create a new one
529 wxString xFontSpec;
530 XFontStruct *font = (XFontStruct *)
531 wxLoadQueryNearestFont(pointSize,
532 M_FONTDATA->m_family,
533 M_FONTDATA->m_style,
534 M_FONTDATA->m_weight,
535 M_FONTDATA->m_underlined,
536 wxT(""),
537 M_FONTDATA->m_encoding,
538 &xFontSpec);
539
540 if ( !font )
541 {
542 wxFAIL_MSG( wxT("Could not allocate even a default font -- something is wrong.") );
543
544 return NULL;
545 }
546
547 wxXFont* f = new wxXFont;
548 #if wxMOTIF_NEW_FONT_HANDLING
549 XFreeFont( (Display*) display, font );
550 #else
551 f->m_fontStruct = (WXFontStructPtr)font;
552 #endif
553 f->m_display = ( display ? display : wxGetDisplay() );
554 f->m_scale = intScale;
555
556 #if wxMOTIF_USE_RENDER_TABLE
557 XmRendition rendition;
558 XmRenderTable renderTable;
559 Arg args[5];
560 int count = 0;
561
562 #if wxMOTIF_NEW_FONT_HANDLING
563 char* fontSpec = wxStrdup(xFontSpec.mb_str());
564 XtSetArg( args[count], XmNfontName, fontSpec ); ++count;
565 XtSetArg( args[count], XmNfontType, XmFONT_IS_FONTSET ); ++count;
566 #else
567 XtSetArg( args[count], XmNfont, font ); ++count;
568 #endif
569 XtSetArg( args[count], XmNunderlineType,
570 GetUnderlined() ? XmSINGLE_LINE : XmNO_LINE ); ++count;
571 rendition = XmRenditionCreate( XmGetXmDisplay( (Display*)f->m_display ),
572 (XmStringTag)"",
573 args, count );
574 renderTable = XmRenderTableAddRenditions( NULL, &rendition, 1,
575 XmMERGE_REPLACE );
576
577 f->m_renderTable = (WXRenderTable)renderTable;
578 f->m_rendition = (WXRendition)rendition;
579 wxASSERT( f->m_renderTable != NULL );
580 #else // if !wxMOTIF_USE_RENDER_TABLE
581 f->m_fontList = XmFontListCreate ((XFontStruct*) font, XmSTRING_DEFAULT_CHARSET);
582 wxASSERT( f->m_fontList != NULL );
583 #endif
584
585 M_FONTDATA->m_fonts.Append(f);
586
587 return f;
588 }
589
590 #if !wxMOTIF_NEW_FONT_HANDLING
591
592 WXFontStructPtr wxFont::GetFontStruct(double scale, WXDisplay* display) const
593 {
594 wxXFont* f = GetInternalFont(scale, display);
595
596 return (f ? f->m_fontStruct : (WXFontStructPtr) 0);
597 }
598
599 #endif
600
601 #if !wxMOTIF_USE_RENDER_TABLE
602
603 WXFontList wxFont::GetFontList(double scale, WXDisplay* display) const
604 {
605 wxXFont* f = GetInternalFont(scale, display);
606
607 return (f ? f->m_fontList : (WXFontList) 0);
608 }
609
610 #else // if wxMOTIF_USE_RENDER_TABLE
611
612 WXRenderTable wxFont::GetRenderTable(WXDisplay* display) const
613 {
614 wxXFont* f = GetInternalFont(1.0, display);
615
616 return (f ? f->m_renderTable : (WXRenderTable) 0);
617 }
618
619 #endif // wxMOTIF_USE_RENDER_TABLE
620
621 WXFontType wxFont::GetFontType(WXDisplay* display) const
622 {
623 #if wxMOTIF_USE_RENDER_TABLE
624 return Ok() ? GetRenderTable(display) : NULL;
625 #else
626 return Ok() ? GetFontList(1.0, display) : NULL;
627 #endif
628 }
629
630 WXFontType wxFont::GetFontTypeC(WXDisplay* display) const
631 {
632 #if wxMOTIF_USE_RENDER_TABLE
633 return Ok() ? GetRenderTable(display) : NULL;
634 #else
635 return Ok() ? XmFontListCopy( (XmFontList)GetFontList(1.0, display) ) : NULL;
636 #endif
637 }
638
639 /*static*/ WXString wxFont::GetFontTag()
640 {
641 #if wxMOTIF_USE_RENDER_TABLE
642 return (WXString)XmNrenderTable;
643 #else
644 return (WXString)XmNfontList;
645 #endif
646 }
647
648 #if wxMOTIF_USE_RENDER_TABLE
649
650 WXFontSet wxFont::GetFontSet(double scale, WXDisplay* display) const
651 {
652 wxXFont* f = GetInternalFont(scale, display);
653
654 if( !f ) return (WXFontSet) 0;
655
656 Arg args[2];
657 int count = 0;
658
659 XtSetArg( args[count], XmNfont, 0 ); ++count;
660 XmRenditionRetrieve( (XmRendition) f->m_rendition, args, count );
661
662 return (WXFontSet) args[0].value;
663 }
664
665 void wxGetTextExtent(WXDisplay* display, const wxFont& font, double scale,
666 const wxString& str,
667 int* width, int* height, int* ascent, int* descent)
668 {
669 XRectangle ink, logical;
670 WXFontSet fset = font.GetFontSet(scale, display);
671
672 XmbTextExtents( (XFontSet)fset, str.mb_str(), str.length(), &ink, &logical);
673
674 if( width ) *width = logical.width;
675 if( height ) *height = logical.height;
676 if( ascent ) *ascent = -logical.y;
677 if( descent ) *descent = logical.height + logical.y;
678 }
679
680 #else // if !wxMOTIF_USE_RENDER_TABLE
681
682 void wxGetTextExtent(WXDisplay* display, const wxFont& font,
683 double scale, const wxString& str,
684 int* width, int* height, int* ascent, int* descent)
685 {
686 WXFontStructPtr pFontStruct = font.GetFontStruct(scale, display);
687
688 int direction, ascent2, descent2;
689 XCharStruct overall;
690 int slen = str.length();
691
692 XTextExtents((XFontStruct*) pFontStruct,
693 const_cast<char*>((const char *)str.mb_str()), slen,
694 &direction, &ascent2, &descent2, &overall);
695
696 if ( width )
697 *width = (overall.width);
698 if ( height )
699 *height = (ascent2 + descent2);
700 if ( descent )
701 *descent = descent2;
702 if ( ascent )
703 *ascent = ascent2;
704 }
705
706 #endif // !wxMOTIF_USE_RENDER_TABLE