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: font.cpp 43545 2006-11-20 16:21:08Z VS $
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
45IMPLEMENT_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
53class wxXFont : public wxObject
54{
55public:
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 && !wxMOTIF_NEW_FONT_HANDLING
63    WXFontList          m_fontList;     // Motif XmFontList
64#else // if wxUSE_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
72class wxFontRefData: public wxGDIRefData
73{
74    friend class wxFont;
75
76public:
77    wxFontRefData(int size = wxDEFAULT,
78                  int family = wxDEFAULT,
79                  int style = wxDEFAULT,
80                  int weight = wxDEFAULT,
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
96protected:
97    // common part of all ctors
98    void Init(int size,
99              int family,
100              int style,
101              int weight,
102              bool underlined,
103              const wxString& faceName,
104              wxFontEncoding encoding);
105
106    // font attributes
107    int           m_pointSize;
108    int           m_family;
109    int           m_style;
110    int           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
129wxXFont::wxXFont()
130{
131#if !wxMOTIF_NEW_FONT_HANDLING
132    m_fontStruct = (WXFontStructPtr) 0;
133#endif
134#if !wxMOTIF_USE_RENDER_TABLE && !wxMOTIF_NEW_FONT_HANDLING
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
144wxXFont::~wxXFont()
145{
146#if !wxMOTIF_USE_RENDER_TABLE
147    if (m_fontList)
148        XmFontListFree ((XmFontList) m_fontList);
149    m_fontList = NULL;
150#else // if wxUSE_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
168void wxFontRefData::Init(int pointSize,
169                         int family,
170                         int style,
171                         int weight,
172                         bool underlined,
173                         const wxString& faceName,
174                         wxFontEncoding encoding)
175{
176    if (family == wxDEFAULT)
177        m_family = wxSWISS;
178    else
179        m_family = family;
180
181    m_faceName = faceName;
182
183    if (style == wxDEFAULT)
184        m_style = wxNORMAL;
185    else
186        m_style = style;
187
188    if (weight == wxDEFAULT)
189        m_weight = wxNORMAL;
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
202wxFontRefData::~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
220wxFont::wxFont(const wxNativeFontInfo& info)
221{
222    (void)Create(info.GetXFontName());
223}
224
225bool wxFont::Create(int pointSize,
226                    int family,
227                    int style,
228                    int 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
240bool 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 = wxBOLD;
264    if (tmp == wxT("BLACK")) M_FONTDATA->m_weight = wxBOLD;
265    if (tmp == wxT("EXTRABOLD")) M_FONTDATA->m_weight = wxBOLD;
266    if (tmp == wxT("DEMIBOLD")) M_FONTDATA->m_weight = wxBOLD;
267    if (tmp == wxT("ULTRABOLD")) M_FONTDATA->m_weight = wxBOLD;
268
269    if (tmp == wxT("LIGHT")) M_FONTDATA->m_weight = wxLIGHT;
270    if (tmp == wxT("THIN")) M_FONTDATA->m_weight = wxLIGHT;
271
272    tmp = tn.GetNextToken().MakeUpper();        // slant
273    if (tmp == wxT("I")) M_FONTDATA->m_style = wxITALIC;
274    if (tmp == wxT("O")) M_FONTDATA->m_style = wxITALIC;
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.c_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 = wxMODERN;
294    else if (M_FONTDATA->m_faceName == wxT("TIMES"))
295        M_FONTDATA->m_family = wxROMAN;
296    else if (M_FONTDATA->m_faceName == wxT("HELVETICA"))
297        M_FONTDATA->m_family = wxSWISS;
298    else if (M_FONTDATA->m_faceName == wxT("LUCIDATYPEWRITER"))
299        M_FONTDATA->m_family = wxTELETYPE;
300    else if (M_FONTDATA->m_faceName == wxT("LUCIDA"))
301        M_FONTDATA->m_family = wxDECORATIVE;
302    else if (M_FONTDATA->m_faceName == wxT("UTOPIA"))
303        M_FONTDATA->m_family = wxSCRIPT;
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 == _T("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 == _T("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 == _T("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
343wxFont::~wxFont()
344{
345}
346
347// ----------------------------------------------------------------------------
348// change the font attributes
349// ----------------------------------------------------------------------------
350
351void wxFont::Unshare()
352{
353    // Don't change shared data
354    if (!m_refData)
355    {
356        m_refData = new wxFontRefData();
357    }
358    else
359    {
360        wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData);
361        UnRef();
362        m_refData = ref;
363    }
364}
365
366void wxFont::SetPointSize(int pointSize)
367{
368    Unshare();
369
370    M_FONTDATA->m_pointSize = pointSize;
371    M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
372}
373
374void wxFont::SetFamily(int family)
375{
376    Unshare();
377
378    M_FONTDATA->m_family = family;
379    M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
380}
381
382void wxFont::SetStyle(int style)
383{
384    Unshare();
385
386    M_FONTDATA->m_style = style;
387    M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
388}
389
390void wxFont::SetWeight(int weight)
391{
392    Unshare();
393
394    M_FONTDATA->m_weight = weight;
395    M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
396}
397
398bool wxFont::SetFaceName(const wxString& faceName)
399{
400    Unshare();
401
402    M_FONTDATA->m_faceName = faceName;
403    M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
404
405    return wxFontBase::SetFaceName(faceName);
406}
407
408void wxFont::SetUnderlined(bool underlined)
409{
410    Unshare();
411
412    M_FONTDATA->m_underlined = underlined;
413}
414
415void wxFont::SetEncoding(wxFontEncoding encoding)
416{
417    Unshare();
418
419    M_FONTDATA->m_encoding = encoding;
420    M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
421}
422
423void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info)
424{
425    Unshare();
426
427    M_FONTDATA->m_nativeFontInfo = info;
428}
429
430// ----------------------------------------------------------------------------
431// query font attributes
432// ----------------------------------------------------------------------------
433
434int wxFont::GetPointSize() const
435{
436    wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
437
438    return M_FONTDATA->m_pointSize;
439}
440
441wxString wxFont::GetFaceName() const
442{
443    wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid font") );
444
445    return M_FONTDATA->m_faceName ;
446}
447
448int wxFont::GetFamily() const
449{
450    wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
451
452    return M_FONTDATA->m_family;
453}
454
455int wxFont::GetStyle() const
456{
457    wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
458
459    return M_FONTDATA->m_style;
460}
461
462int wxFont::GetWeight() const
463{
464    wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
465
466    return M_FONTDATA->m_weight;
467}
468
469bool wxFont::GetUnderlined() const
470{
471    wxCHECK_MSG( Ok(), false, wxT("invalid font") );
472
473    return M_FONTDATA->m_underlined;
474}
475
476wxFontEncoding wxFont::GetEncoding() const
477{
478    wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, wxT("invalid font") );
479
480    return M_FONTDATA->m_encoding;
481}
482
483const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
484{
485    wxCHECK_MSG( Ok(), (wxNativeFontInfo *)NULL, wxT("invalid font") );
486
487    if(M_FONTDATA->m_nativeFontInfo.GetXFontName().empty())
488        GetInternalFont();
489
490    return &(M_FONTDATA->m_nativeFontInfo);
491}
492
493// ----------------------------------------------------------------------------
494// real implementation
495// ----------------------------------------------------------------------------
496
497// Find an existing, or create a new, XFontStruct
498// based on this wxFont and the given scale. Append the
499// font to list in the private data for future reference.
500wxXFont* wxFont::GetInternalFont(double scale, WXDisplay* display) const
501{
502    if ( !Ok() )
503        return (wxXFont *)NULL;
504
505    long intScale = long(scale * 100.0 + 0.5); // key for wxXFont
506    int pointSize = (M_FONTDATA->m_pointSize * 10 * intScale) / 100;
507
508    // search existing fonts first
509    wxList::compatibility_iterator node = M_FONTDATA->m_fonts.GetFirst();
510    while (node)
511    {
512        wxXFont* f = (wxXFont*) node->GetData();
513        if ((!display || (f->m_display == display)) && (f->m_scale == intScale))
514            return f;
515        node = node->GetNext();
516    }
517
518    // not found, create a new one
519    wxString xFontSpec;
520    XFontStruct *font = (XFontStruct *)
521                        wxLoadQueryNearestFont(pointSize,
522                                               M_FONTDATA->m_family,
523                                               M_FONTDATA->m_style,
524                                               M_FONTDATA->m_weight,
525                                               M_FONTDATA->m_underlined,
526                                               wxT(""),
527                                               M_FONTDATA->m_encoding,
528                                               &xFontSpec);
529
530    if ( !font )
531    {
532        wxFAIL_MSG( wxT("Could not allocate even a default font -- something is wrong.") );
533
534        return (wxXFont*) NULL;
535    }
536
537    wxXFont* f = new wxXFont;
538#if wxMOTIF_NEW_FONT_HANDLING
539    XFreeFont( (Display*) display, font );
540#else
541    f->m_fontStruct = (WXFontStructPtr)font;
542#endif
543    f->m_display = ( display ? display : wxGetDisplay() );
544    f->m_scale = intScale;
545
546#if wxMOTIF_USE_RENDER_TABLE
547    XmRendition rendition;
548    XmRenderTable renderTable;
549    Arg args[5];
550    int count = 0;
551
552#if wxMOTIF_NEW_FONT_HANDLING
553    wxChar* fontSpec = wxStrdup( xFontSpec.c_str() );
554    XtSetArg( args[count], XmNfontName, fontSpec ); ++count;
555    XtSetArg( args[count], XmNfontType, XmFONT_IS_FONTSET ); ++count;
556#else
557    XtSetArg( args[count], XmNfont, font ); ++count;
558#endif
559    XtSetArg( args[count], XmNunderlineType,
560              GetUnderlined() ? XmSINGLE_LINE : XmNO_LINE ); ++count;
561    rendition = XmRenditionCreate( XmGetXmDisplay( (Display*)f->m_display ),
562                                   (XmStringTag)"",
563                                   args, count );
564    renderTable = XmRenderTableAddRenditions( NULL, &rendition, 1,
565                                              XmMERGE_REPLACE );
566
567    f->m_renderTable = (WXRenderTable)renderTable;
568    f->m_rendition = (WXRendition)rendition;
569    wxASSERT( f->m_renderTable != NULL );
570#else // if !wxMOTIF_USE_RENDER_TABLE
571    f->m_fontList = XmFontListCreate ((XFontStruct*) font, XmSTRING_DEFAULT_CHARSET);
572    wxASSERT( f->m_fontList != NULL );
573#endif
574
575    M_FONTDATA->m_fonts.Append(f);
576
577    return f;
578}
579
580#if !wxMOTIF_NEW_FONT_HANDLING
581
582WXFontStructPtr wxFont::GetFontStruct(double scale, WXDisplay* display) const
583{
584    wxXFont* f = GetInternalFont(scale, display);
585
586    return (f ? f->m_fontStruct : (WXFontStructPtr) 0);
587}
588
589#endif
590
591#if !wxMOTIF_USE_RENDER_TABLE
592
593WXFontList wxFont::GetFontList(double scale, WXDisplay* display) const
594{
595    wxXFont* f = GetInternalFont(scale, display);
596
597    return (f ? f->m_fontList : (WXFontList) 0);
598}
599
600#else // if wxMOTIF_USE_RENDER_TABLE
601
602WXRenderTable wxFont::GetRenderTable(WXDisplay* display) const
603{
604    wxXFont* f = GetInternalFont(1.0, display);
605
606    return (f ? f->m_renderTable : (WXRenderTable) 0);
607}
608
609#endif // wxMOTIF_USE_RENDER_TABLE
610
611WXFontType wxFont::GetFontType(WXDisplay* display) const
612{
613#if wxMOTIF_USE_RENDER_TABLE
614    return Ok() ? GetRenderTable(display) : NULL;
615#else
616    return Ok() ? GetFontList(1.0, display) : NULL;
617#endif
618}
619
620WXFontType wxFont::GetFontTypeC(WXDisplay* display) const
621{
622#if wxMOTIF_USE_RENDER_TABLE
623    return Ok() ? GetRenderTable(display) : NULL;
624#else
625    return Ok() ? XmFontListCopy( (XmFontList)GetFontList(1.0, display) ) : NULL;
626#endif
627}
628
629/*static*/ WXString wxFont::GetFontTag()
630{
631#if wxMOTIF_USE_RENDER_TABLE
632    return (WXString)XmNrenderTable;
633#else
634    return (WXString)XmNfontList;
635#endif
636}
637
638#if wxMOTIF_NEW_FONT_HANDLING
639
640WXFontSet wxFont::GetFontSet(double scale, WXDisplay* display) const
641{
642    wxXFont* f = GetInternalFont(scale, display);
643
644    if( !f ) return (WXFontSet) 0;
645
646    Arg args[2];
647    int count = 0;
648
649    XtSetArg( args[count], XmNfont, 0 ); ++count;
650    XmRenditionRetrieve( (XmRendition) f->m_rendition, args, count );
651
652    return (WXFontSet) args[0].value;
653}
654
655void wxGetTextExtent(WXDisplay* display, const wxFont& font, double scale,
656                     const wxString& str,
657                     int* width, int* height, int* ascent, int* descent)
658{
659    XRectangle ink, logical;
660    WXFontSet fset = font.GetFontSet(scale, display);
661
662    XmbTextExtents( (XFontSet)fset, str.c_str(), str.length(), &ink, &logical);
663
664    if( width ) *width = logical.width;
665    if( height ) *height = logical.height;
666    if( ascent ) *ascent = -logical.y;
667    if( descent ) *descent = logical.height + logical.y;
668}
669
670#else // if !wxMOTIF_NEW_FONT_HANDLING
671
672void wxGetTextExtent(WXDisplay* display, const wxFont& font,
673                     double scale, const wxString& str,
674                     int* width, int* height, int* ascent, int* descent)
675{
676    WXFontStructPtr pFontStruct = font.GetFontStruct(scale, display);
677
678    int direction, ascent2, descent2;
679    XCharStruct overall;
680    int slen = str.length();
681
682    XTextExtents((XFontStruct*) pFontStruct, (char*) str.c_str(), slen,
683                 &direction, &ascent2, &descent2, &overall);
684
685    if ( width )
686        *width = (overall.width);
687    if ( height )
688        *height = (ascent2 + descent2);
689    if ( descent )
690        *descent = descent2;
691    if ( ascent )
692        *ascent = ascent2;
693}
694
695#endif // !wxMOTIF_NEW_FONT_HANDLING
696