1///////////////////////////////////////////////////////////////////////////// 2// Name: src/gtk1/font.cpp 3// Purpose: 4// Author: Robert Roebling 5// Id: $Id: font.cpp 43545 2006-11-20 16:21:08Z VS $ 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/settings.h" 26 #include "wx/cmndata.h" 27 #include "wx/gdicmn.h" 28#endif 29 30#include "wx/fontutil.h" 31#include "wx/utils.h" 32#include "wx/tokenzr.h" 33 34#include <strings.h> 35 36#include "wx/gtk1/private.h" 37#include <gdk/gdkprivate.h> 38 39// ---------------------------------------------------------------------------- 40// constants 41// ---------------------------------------------------------------------------- 42 43// the default size (in points) for the fonts 44static const int wxDEFAULT_FONT_SIZE = 12; 45 46// ---------------------------------------------------------------------------- 47// wxScaledFontList: maps the font sizes to the GDK fonts for the given font 48// ---------------------------------------------------------------------------- 49 50WX_DECLARE_HASH_MAP(int, GdkFont *, wxIntegerHash, wxIntegerEqual, 51 wxScaledFontList); 52 53// ---------------------------------------------------------------------------- 54// wxFontRefData 55// ---------------------------------------------------------------------------- 56 57class wxFontRefData : public wxObjectRefData 58{ 59public: 60 // from broken down font parameters, also default ctor 61 wxFontRefData(int size = -1, 62 int family = wxFONTFAMILY_DEFAULT, 63 int style = wxFONTSTYLE_NORMAL, 64 int weight = wxFONTWEIGHT_NORMAL, 65 bool underlined = false, 66 const wxString& faceName = wxEmptyString, 67 wxFontEncoding encoding = wxFONTENCODING_DEFAULT); 68 69 // from XFLD 70 wxFontRefData(const wxString& fontname); 71 72 // copy ctor 73 wxFontRefData( const wxFontRefData& data ); 74 75 virtual ~wxFontRefData(); 76 77 // do we have the native font info? 78 bool HasNativeFont() const 79 { 80 // only use m_nativeFontInfo if it had been initialized 81 return !m_nativeFontInfo.IsDefault(); 82 } 83 84 // setters: all of them also take care to modify m_nativeFontInfo if we 85 // have it so as to not lose the information not carried by our fields 86 void SetPointSize(int pointSize); 87 void SetFamily(int family); 88 void SetStyle(int style); 89 void SetWeight(int weight); 90 void SetUnderlined(bool underlined); 91 bool SetFaceName(const wxString& facename); 92 void SetEncoding(wxFontEncoding encoding); 93 94 void SetNoAntiAliasing( bool no = true ) { m_noAA = no; } 95 bool GetNoAntiAliasing() const { return m_noAA; } 96 97 // and this one also modifies all the other font data fields 98 void SetNativeFontInfo(const wxNativeFontInfo& info); 99 100 // debugger helper: shows what the font really is 101 // 102 // VZ: I need this as my gdb either shows wildly wrong values or crashes 103 // when I ask it to "p fontRefData" :-( 104#if defined(__WXDEBUG__) 105 void Dump() const 106 { 107 wxPrintf(_T("%s-%s-%s-%d-%d\n"), 108 m_faceName.c_str(), 109 m_weight == wxFONTWEIGHT_NORMAL 110 ? _T("normal") 111 : m_weight == wxFONTWEIGHT_BOLD 112 ? _T("bold") 113 : _T("light"), 114 m_style == wxFONTSTYLE_NORMAL ? _T("regular") : _T("italic"), 115 m_pointSize, 116 m_encoding); 117 } 118#endif // Debug 119 120protected: 121 // common part of all ctors 122 void Init(int pointSize, 123 int family, 124 int style, 125 int weight, 126 bool underlined, 127 const wxString& faceName, 128 wxFontEncoding encoding); 129 130 // set all fields from (already initialized and valid) m_nativeFontInfo 131 void InitFromNative(); 132 133private: 134 // clear m_scaled_xfonts if any 135 void ClearGdkFonts(); 136 137 // the map of font sizes to "GdkFont *" 138 wxScaledFontList m_scaled_xfonts; 139 140 int m_pointSize; 141 int m_family, 142 m_style, 143 m_weight; 144 bool m_underlined; 145 wxString m_faceName; 146 wxFontEncoding m_encoding; // Unused under GTK 2.0 147 bool m_noAA; // No anti-aliasing 148 149 // The native font info, basicly an XFLD under GTK 1.2 and 150 // the pango font description under GTK 2.0. 151 wxNativeFontInfo m_nativeFontInfo; 152 153 friend class wxFont; 154}; 155 156#define M_FONTDATA ((wxFontRefData*)m_refData) 157 158// ---------------------------------------------------------------------------- 159// wxFontRefData 160// ---------------------------------------------------------------------------- 161 162void wxFontRefData::Init(int pointSize, 163 int family, 164 int style, 165 int weight, 166 bool underlined, 167 const wxString& faceName, 168 wxFontEncoding encoding) 169{ 170 m_family = family == wxFONTFAMILY_DEFAULT ? wxFONTFAMILY_SWISS : family; 171 172 m_faceName = faceName; 173 174 // we accept both wxDEFAULT and wxNORMAL here - should we? 175 m_style = style == wxDEFAULT ? wxFONTSTYLE_NORMAL : style; 176 m_weight = weight == wxDEFAULT ? wxFONTWEIGHT_NORMAL : weight; 177 178 // and here, do we really want to forbid creation of the font of the size 179 // 90 (the value of wxDEFAULT)?? 180 m_pointSize = pointSize == wxDEFAULT || pointSize == -1 181 ? wxDEFAULT_FONT_SIZE 182 : pointSize; 183 184 m_underlined = underlined; 185 m_encoding = encoding; 186 187 m_noAA = false; 188} 189 190void wxFontRefData::InitFromNative() 191{ 192 m_noAA = false; 193 194 // get the font parameters from the XLFD 195 // ------------------------------------- 196 197 m_faceName = m_nativeFontInfo.GetXFontComponent(wxXLFD_FAMILY); 198 199 m_weight = wxFONTWEIGHT_NORMAL; 200 201 wxString w = m_nativeFontInfo.GetXFontComponent(wxXLFD_WEIGHT).Upper(); 202 if ( !w.empty() && w != _T('*') ) 203 { 204 // the test below catches all of BOLD, EXTRABOLD, DEMIBOLD, ULTRABOLD 205 // and BLACK 206 if ( ((w[0u] == _T('B') && (!wxStrcmp(w.c_str() + 1, wxT("OLD")) || 207 !wxStrcmp(w.c_str() + 1, wxT("LACK"))))) || 208 wxStrstr(w.c_str() + 1, _T("BOLD")) ) 209 { 210 m_weight = wxFONTWEIGHT_BOLD; 211 } 212 else if ( w == _T("LIGHT") || w == _T("THIN") ) 213 { 214 m_weight = wxFONTWEIGHT_LIGHT; 215 } 216 } 217 218 switch ( wxToupper(*m_nativeFontInfo. 219 GetXFontComponent(wxXLFD_SLANT).c_str()) ) 220 { 221 case _T('I'): // italique 222 m_style = wxFONTSTYLE_ITALIC; 223 break; 224 225 case _T('O'): // oblique 226 m_style = wxFONTSTYLE_SLANT; 227 break; 228 229 default: 230 m_style = wxFONTSTYLE_NORMAL; 231 } 232 233 long ptSize; 234 if ( m_nativeFontInfo.GetXFontComponent(wxXLFD_POINTSIZE).ToLong(&ptSize) ) 235 { 236 // size in XLFD is in 10 point units 237 m_pointSize = (int)(ptSize / 10); 238 } 239 else 240 { 241 m_pointSize = wxDEFAULT_FONT_SIZE; 242 } 243 244 // examine the spacing: if the font is monospaced, assume wxTELETYPE 245 // family for compatibility with the old code which used it instead of 246 // IsFixedWidth() 247 if ( m_nativeFontInfo.GetXFontComponent(wxXLFD_SPACING).Upper() == _T('M') ) 248 { 249 m_family = wxFONTFAMILY_TELETYPE; 250 } 251 else // not monospaceed 252 { 253 // don't even try guessing it, it doesn't work for too many fonts 254 // anyhow 255 m_family = wxFONTFAMILY_UNKNOWN; 256 } 257 258 // X fonts are never underlined... 259 m_underlined = false; 260 261 // deal with font encoding 262 wxString 263 registry = m_nativeFontInfo.GetXFontComponent(wxXLFD_REGISTRY).Upper(), 264 encoding = m_nativeFontInfo.GetXFontComponent(wxXLFD_ENCODING).Upper(); 265 266 if ( registry == _T("ISO8859") ) 267 { 268 int cp; 269 if ( wxSscanf(encoding, wxT("%d"), &cp) == 1 ) 270 { 271 m_encoding = (wxFontEncoding)(wxFONTENCODING_ISO8859_1 + cp - 1); 272 } 273 } 274 else if ( registry == _T("MICROSOFT") ) 275 { 276 int cp; 277 if ( wxSscanf(encoding, wxT("cp125%d"), &cp) == 1 ) 278 { 279 m_encoding = (wxFontEncoding)(wxFONTENCODING_CP1250 + cp); 280 } 281 } 282 else if ( registry == _T("KOI8") ) 283 { 284 m_encoding = wxFONTENCODING_KOI8; 285 } 286 else // unknown encoding 287 { 288 // may be give a warning here? or use wxFontMapper? 289 m_encoding = wxFONTENCODING_SYSTEM; 290 } 291} 292 293wxFontRefData::wxFontRefData( const wxFontRefData& data ) 294 : wxObjectRefData() 295{ 296 m_pointSize = data.m_pointSize; 297 m_family = data.m_family; 298 m_style = data.m_style; 299 m_weight = data.m_weight; 300 301 m_underlined = data.m_underlined; 302 303 m_faceName = data.m_faceName; 304 m_encoding = data.m_encoding; 305 306 m_noAA = data.m_noAA; 307 308 // Forces a copy of the internal data. wxNativeFontInfo should probably 309 // have a copy ctor and assignment operator to fix this properly but that 310 // would break binary compatibility... 311 m_nativeFontInfo.FromString(data.m_nativeFontInfo.ToString()); 312} 313 314wxFontRefData::wxFontRefData(int size, int family, int style, 315 int weight, bool underlined, 316 const wxString& faceName, 317 wxFontEncoding encoding) 318{ 319 Init(size, family, style, weight, underlined, faceName, encoding); 320} 321 322wxFontRefData::wxFontRefData(const wxString& fontname) 323{ 324 // FromString() should really work in GTK1 too, doesn't it? 325 m_nativeFontInfo.SetXFontName(fontname); 326 327 InitFromNative(); 328} 329 330void wxFontRefData::ClearGdkFonts() 331{ 332 for ( wxScaledFontList::iterator i = m_scaled_xfonts.begin(); 333 i != m_scaled_xfonts.end(); 334 ++i ) 335 { 336 GdkFont *font = i->second; 337 gdk_font_unref( font ); 338 } 339 340 m_scaled_xfonts.clear(); 341} 342 343wxFontRefData::~wxFontRefData() 344{ 345 ClearGdkFonts(); 346} 347 348// ---------------------------------------------------------------------------- 349// wxFontRefData SetXXX() 350// ---------------------------------------------------------------------------- 351 352void wxFontRefData::SetPointSize(int pointSize) 353{ 354 m_pointSize = pointSize; 355 356 if ( HasNativeFont() ) 357 { 358 wxString size; 359 if ( pointSize == -1 ) 360 size = _T('*'); 361 else 362 size.Printf(_T("%d"), 10*pointSize); 363 364 m_nativeFontInfo.SetXFontComponent(wxXLFD_POINTSIZE, size); 365 } 366} 367 368void wxFontRefData::SetFamily(int family) 369{ 370 m_family = family; 371 372 // TODO: what are we supposed to do with m_nativeFontInfo here? 373} 374 375void wxFontRefData::SetStyle(int style) 376{ 377 m_style = style; 378 379 if ( HasNativeFont() ) 380 { 381 wxString slant; 382 switch ( style ) 383 { 384 case wxFONTSTYLE_ITALIC: 385 slant = _T('i'); 386 break; 387 388 case wxFONTSTYLE_SLANT: 389 slant = _T('o'); 390 break; 391 392 default: 393 wxFAIL_MSG( _T("unknown font style") ); 394 // fall through 395 396 case wxFONTSTYLE_NORMAL: 397 slant = _T('r'); 398 } 399 400 m_nativeFontInfo.SetXFontComponent(wxXLFD_SLANT, slant); 401 } 402} 403 404void wxFontRefData::SetWeight(int weight) 405{ 406 m_weight = weight; 407 408 if ( HasNativeFont() ) 409 { 410 wxString boldness; 411 switch ( weight ) 412 { 413 case wxFONTWEIGHT_BOLD: 414 boldness = _T("bold"); 415 break; 416 417 case wxFONTWEIGHT_LIGHT: 418 boldness = _T("light"); 419 break; 420 421 default: 422 wxFAIL_MSG( _T("unknown font weight") ); 423 // fall through 424 425 case wxFONTWEIGHT_NORMAL: 426 // unspecified 427 boldness = _T("medium"); 428 } 429 430 m_nativeFontInfo.SetXFontComponent(wxXLFD_WEIGHT, boldness); 431 } 432} 433 434void wxFontRefData::SetUnderlined(bool underlined) 435{ 436 m_underlined = underlined; 437 438 // the XLFD doesn't have "underlined" field anyhow 439} 440 441bool wxFontRefData::SetFaceName(const wxString& facename) 442{ 443 m_faceName = facename; 444 445 if ( HasNativeFont() ) 446 { 447 m_nativeFontInfo.SetXFontComponent(wxXLFD_FAMILY, facename); 448 } 449 450 return true; 451} 452 453void wxFontRefData::SetEncoding(wxFontEncoding encoding) 454{ 455 m_encoding = encoding; 456 457 if ( HasNativeFont() ) 458 { 459 wxNativeEncodingInfo info; 460 if ( wxGetNativeFontEncoding(encoding, &info) ) 461 { 462 m_nativeFontInfo.SetXFontComponent(wxXLFD_REGISTRY, info.xregistry); 463 m_nativeFontInfo.SetXFontComponent(wxXLFD_ENCODING, info.xencoding); 464 } 465 } 466} 467 468void wxFontRefData::SetNativeFontInfo(const wxNativeFontInfo& info) 469{ 470 // previously cached fonts shouldn't be used 471 ClearGdkFonts(); 472 473 m_nativeFontInfo = info; 474 475 // set all the other font parameters from the native font info 476 InitFromNative(); 477} 478 479// ---------------------------------------------------------------------------- 480// wxFont creation 481// ---------------------------------------------------------------------------- 482 483IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject) 484 485wxFont::wxFont(const wxNativeFontInfo& info) 486{ 487 (void) Create(info.GetXFontName()); 488} 489 490bool wxFont::Create( int pointSize, 491 int family, 492 int style, 493 int weight, 494 bool underlined, 495 const wxString& face, 496 wxFontEncoding encoding) 497{ 498 UnRef(); 499 500 m_refData = new wxFontRefData(pointSize, family, style, weight, 501 underlined, face, encoding); 502 503 return true; 504} 505 506bool wxFont::Create(const wxString& fontname) 507{ 508 // VZ: does this really happen? 509 if ( fontname.empty() ) 510 { 511 *this = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); 512 513 return true; 514 } 515 516 m_refData = new wxFontRefData(fontname); 517 518 return true; 519} 520 521void wxFont::Unshare() 522{ 523 if (!m_refData) 524 { 525 m_refData = new wxFontRefData(); 526 } 527 else 528 { 529 wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData); 530 UnRef(); 531 m_refData = ref; 532 } 533} 534 535wxFont::~wxFont() 536{ 537} 538 539// ---------------------------------------------------------------------------- 540// accessors 541// ---------------------------------------------------------------------------- 542 543int wxFont::GetPointSize() const 544{ 545 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 546 547 return M_FONTDATA->m_pointSize; 548} 549 550wxString wxFont::GetFaceName() const 551{ 552 wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid font") ); 553 554 return M_FONTDATA->m_faceName; 555} 556 557int wxFont::GetFamily() const 558{ 559 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 560 561 return M_FONTDATA->m_family; 562} 563 564int wxFont::GetStyle() const 565{ 566 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 567 568 return M_FONTDATA->m_style; 569} 570 571int wxFont::GetWeight() const 572{ 573 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 574 575 return M_FONTDATA->m_weight; 576} 577 578bool wxFont::GetUnderlined() const 579{ 580 wxCHECK_MSG( Ok(), false, wxT("invalid font") ); 581 582 return M_FONTDATA->m_underlined; 583} 584 585wxFontEncoding wxFont::GetEncoding() const 586{ 587 wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, wxT("invalid font") ); 588 589 // m_encoding is unused in wxGTK2, return encoding that the user set. 590 return M_FONTDATA->m_encoding; 591} 592 593bool wxFont::GetNoAntiAliasing() const 594{ 595 wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, wxT("invalid font") ); 596 597 return M_FONTDATA->m_noAA; 598} 599 600const wxNativeFontInfo *wxFont::GetNativeFontInfo() const 601{ 602 wxCHECK_MSG( Ok(), (wxNativeFontInfo *)NULL, wxT("invalid font") ); 603 604 if ( !M_FONTDATA->HasNativeFont() ) 605 { 606 // NB: this call has important side-effect: it not only finds 607 // GdkFont representation, it also initializes m_nativeFontInfo 608 // by calling its SetXFontName method 609 GetInternalFont(); 610 } 611 612 return &(M_FONTDATA->m_nativeFontInfo); 613} 614 615bool wxFont::IsFixedWidth() const 616{ 617 wxCHECK_MSG( Ok(), false, wxT("invalid font") ); 618 619 if ( M_FONTDATA->HasNativeFont() ) 620 { 621 // the monospace fonts are supposed to have "M" in the spacing field 622 wxString spacing = M_FONTDATA-> 623 m_nativeFontInfo.GetXFontComponent(wxXLFD_SPACING); 624 625 return spacing.Upper() == _T('M'); 626 } 627 628 return wxFontBase::IsFixedWidth(); 629} 630 631// ---------------------------------------------------------------------------- 632// change font attributes 633// ---------------------------------------------------------------------------- 634 635void wxFont::SetPointSize(int pointSize) 636{ 637 Unshare(); 638 639 M_FONTDATA->SetPointSize(pointSize); 640} 641 642void wxFont::SetFamily(int family) 643{ 644 Unshare(); 645 646 M_FONTDATA->SetFamily(family); 647} 648 649void wxFont::SetStyle(int style) 650{ 651 Unshare(); 652 653 M_FONTDATA->SetStyle(style); 654} 655 656void wxFont::SetWeight(int weight) 657{ 658 Unshare(); 659 660 M_FONTDATA->SetWeight(weight); 661} 662 663bool wxFont::SetFaceName(const wxString& faceName) 664{ 665 Unshare(); 666 667 return M_FONTDATA->SetFaceName(faceName) && 668 wxFontBase::SetFaceName(faceName); 669} 670 671void wxFont::SetUnderlined(bool underlined) 672{ 673 Unshare(); 674 675 M_FONTDATA->SetUnderlined(underlined); 676} 677 678void wxFont::SetEncoding(wxFontEncoding encoding) 679{ 680 Unshare(); 681 682 M_FONTDATA->SetEncoding(encoding); 683} 684 685void wxFont::DoSetNativeFontInfo( const wxNativeFontInfo& info ) 686{ 687 Unshare(); 688 689 M_FONTDATA->SetNativeFontInfo( info ); 690} 691 692void wxFont::SetNoAntiAliasing( bool no ) 693{ 694 Unshare(); 695 696 M_FONTDATA->SetNoAntiAliasing( no ); 697} 698 699// ---------------------------------------------------------------------------- 700// get internal representation of font 701// ---------------------------------------------------------------------------- 702 703static GdkFont *g_systemDefaultGuiFont = (GdkFont*) NULL; 704 705// this is also used from tbargtk.cpp and tooltip.cpp, hence extern 706extern GdkFont *GtkGetDefaultGuiFont() 707{ 708 if (!g_systemDefaultGuiFont) 709 { 710 GtkWidget *widget = gtk_button_new(); 711 GtkStyle *def = gtk_rc_get_style( widget ); 712 if (def) 713 { 714 g_systemDefaultGuiFont = gdk_font_ref( def->font ); 715 } 716 else 717 { 718 def = gtk_widget_get_default_style(); 719 if (def) 720 g_systemDefaultGuiFont = gdk_font_ref( def->font ); 721 } 722 gtk_widget_destroy( widget ); 723 } 724 else 725 { 726 // already have it, but ref it once more before returning 727 gdk_font_ref(g_systemDefaultGuiFont); 728 } 729 730 return g_systemDefaultGuiFont; 731} 732 733GdkFont *wxFont::GetInternalFont( float scale ) const 734{ 735 GdkFont *font = (GdkFont *) NULL; 736 737 wxCHECK_MSG( Ok(), font, wxT("invalid font") ); 738 739 long int_scale = long(scale * 100.0 + 0.5); // key for fontlist 740 int point_scale = (int)((M_FONTDATA->m_pointSize * 10 * int_scale) / 100); 741 742 wxScaledFontList& list = M_FONTDATA->m_scaled_xfonts; 743 wxScaledFontList::iterator i = list.find(int_scale); 744 if ( i != list.end() ) 745 { 746 font = i->second; 747 } 748 else // we don't have this font in this size yet 749 { 750 if (*this == wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT)) 751 { 752 font = GtkGetDefaultGuiFont(); 753 } 754 755 if ( !font ) 756 { 757 // do we have the XLFD? 758 if ( int_scale == 100 && M_FONTDATA->HasNativeFont() ) 759 { 760 font = wxLoadFont(M_FONTDATA->m_nativeFontInfo.GetXFontName()); 761 } 762 763 // no XLFD of no exact match - try the approximate one now 764 if ( !font ) 765 { 766 wxString xfontname; 767 font = wxLoadQueryNearestFont( point_scale, 768 M_FONTDATA->m_family, 769 M_FONTDATA->m_style, 770 M_FONTDATA->m_weight, 771 M_FONTDATA->m_underlined, 772 M_FONTDATA->m_faceName, 773 M_FONTDATA->m_encoding, 774 &xfontname); 775 // NB: wxFont::GetNativeFontInfo relies on this 776 // side-effect of GetInternalFont 777 if ( int_scale == 100 ) 778 M_FONTDATA->m_nativeFontInfo.SetXFontName(xfontname); 779 } 780 } 781 782 if ( font ) 783 { 784 list[int_scale] = font; 785 } 786 } 787 788 // it's quite useless to make it a wxCHECK because we're going to crash 789 // anyhow... 790 wxASSERT_MSG( font, wxT("could not load any font?") ); 791 792 return font; 793} 794