source: trunk/src/gui/text/qfont.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 84.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfont.h"
43#include "qdebug.h"
44#include "qpaintdevice.h"
45#include "qfontdatabase.h"
46#include "qfontmetrics.h"
47#include "qfontinfo.h"
48#include "qpainter.h"
49#include "qhash.h"
50#include "qdatastream.h"
51#include "qapplication.h"
52#include "qstringlist.h"
53
54#include "qthread.h"
55#include "qthreadstorage.h"
56
57#include <private/qunicodetables_p.h>
58#include "qfont_p.h"
59#include <private/qfontengine_p.h>
60#include <private/qpainter_p.h>
61#include <private/qtextengine_p.h>
62#include <limits.h>
63
64#ifdef Q_WS_X11
65#include "qx11info_x11.h"
66#include <private/qt_x11_p.h>
67#endif
68#ifdef Q_WS_PM
69#include "qt_os2.h"
70#include "qwindowdefs_pm.h"
71#endif
72#ifdef Q_WS_QWS
73#include "qscreen_qws.h"
74#if !defined(QT_NO_QWS_QPF2)
75#include <qfile.h>
76#include "qfontengine_qpf_p.h"
77#endif
78#endif
79#ifdef Q_OS_SYMBIAN
80#include "qt_s60_p.h"
81#endif
82
83#include <QMutexLocker>
84
85// #define QFONTCACHE_DEBUG
86#ifdef QFONTCACHE_DEBUG
87# define FC_DEBUG qDebug
88#else
89# define FC_DEBUG if (false) qDebug
90#endif
91
92QT_BEGIN_NAMESPACE
93
94#ifdef Q_WS_WIN
95extern HDC shared_dc();
96#endif
97
98#ifdef Q_WS_X11
99extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
100#endif
101
102bool QFontDef::exactMatch(const QFontDef &other) const
103{
104 /*
105 QFontDef comparison is more complicated than just simple
106 per-member comparisons.
107
108 When comparing point/pixel sizes, either point or pixelsize
109 could be -1. in This case we have to compare the non negative
110 size value.
111
112 This test will fail if the point-sizes differ by 1/2 point or
113 more or they do not round to the same value. We have to do this
114 since our API still uses 'int' point-sizes in the API, but store
115 deci-point-sizes internally.
116
117 To compare the family members, we need to parse the font names
118 and compare the family/foundry strings separately. This allows
119 us to compare e.g. "Helvetica" and "Helvetica [Adobe]" with
120 positive results.
121 */
122 if (pixelSize != -1 && other.pixelSize != -1) {
123 if (pixelSize != other.pixelSize)
124 return false;
125 } else if (pointSize != -1 && other.pointSize != -1) {
126 if (pointSize != other.pointSize)
127 return false;
128 } else {
129 return false;
130 }
131
132 if (!ignorePitch && !other.ignorePitch && fixedPitch != other.fixedPitch)
133 return false;
134
135 if (stretch != 0 && other.stretch != 0 && stretch != other.stretch)
136 return false;
137
138 QString this_family, this_foundry, other_family, other_foundry;
139 QFontDatabase::parseFontName(family, this_foundry, this_family);
140 QFontDatabase::parseFontName(other.family, other_foundry, other_family);
141
142 return (styleHint == other.styleHint
143 && styleStrategy == other.styleStrategy
144 && weight == other.weight
145 && style == other.style
146 && this_family == other_family
147 && (this_foundry.isEmpty()
148 || other_foundry.isEmpty()
149 || this_foundry == other_foundry)
150#ifdef Q_WS_X11
151 && addStyle == other.addStyle
152#endif // Q_WS_X11
153 );
154}
155
156extern bool qt_is_gui_used;
157
158Q_GUI_EXPORT int qt_defaultDpiX()
159{
160 if (!qt_is_gui_used)
161 return 75;
162
163 int dpi;
164#ifdef Q_WS_X11
165 dpi = QX11Info::appDpiX();
166#elif defined(Q_WS_WIN)
167 dpi = GetDeviceCaps(shared_dc(),LOGPIXELSX);
168#elif defined(Q_WS_PM)
169 LONG ulDpi;
170 DevQueryCaps(GpiQueryDevice(qt_display_ps()),
171 CAPS_HORIZONTAL_FONT_RES, 1, &ulDpi);
172 Q_ASSERT(ulDpi != 0);
173 dpi = ulDpi;
174#elif defined(Q_WS_MAC)
175 extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
176 dpi = qt_mac_defaultDpi_x();
177#elif defined(Q_WS_QWS)
178 if (!qt_screen)
179 return 72;
180 QScreen *screen = qt_screen;
181 const QList<QScreen*> subScreens = qt_screen->subScreens();
182 if (!subScreens.isEmpty())
183 screen = subScreens.at(0);
184 dpi = qRound(screen->width() / (screen->physicalWidth() / qreal(25.4)));
185#elif defined(Q_OS_SYMBIAN)
186 dpi = S60->defaultDpiX;
187#endif // Q_WS_X11
188
189 return dpi;
190}
191
192Q_GUI_EXPORT int qt_defaultDpiY()
193{
194 if (!qt_is_gui_used)
195 return 75;
196
197 int dpi;
198#ifdef Q_WS_X11
199 dpi = QX11Info::appDpiY();
200#elif defined(Q_WS_WIN)
201 dpi = GetDeviceCaps(shared_dc(),LOGPIXELSY);
202#elif defined(Q_WS_PM)
203 LONG ulDpi;
204 DevQueryCaps(GpiQueryDevice(qt_display_ps()),
205 CAPS_VERTICAL_FONT_RES, 1, &ulDpi);
206 Q_ASSERT(ulDpi != 0);
207 dpi = ulDpi;
208#elif defined(Q_WS_MAC)
209 extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp
210 dpi = qt_mac_defaultDpi_y();
211#elif defined(Q_WS_QWS)
212 if (!qt_screen)
213 return 72;
214 QScreen *screen = qt_screen;
215 const QList<QScreen*> subScreens = qt_screen->subScreens();
216 if (!subScreens.isEmpty())
217 screen = subScreens.at(0);
218 dpi = qRound(screen->height() / (screen->physicalHeight() / qreal(25.4)));
219#elif defined(Q_OS_SYMBIAN)
220 dpi = S60->defaultDpiY;
221#endif // Q_WS_X11
222
223 return dpi;
224}
225
226Q_GUI_EXPORT int qt_defaultDpi()
227{
228 return qt_defaultDpiY();
229}
230
231QFontPrivate::QFontPrivate()
232 : engineData(0), dpi(qt_defaultDpi()), screen(0),
233 rawMode(false), underline(false), overline(false), strikeOut(false), kerning(true),
234 capital(0), letterSpacingIsAbsolute(false), scFont(0)
235{
236#ifdef Q_WS_X11
237 if (QX11Info::display())
238 screen = QX11Info::appScreen();
239 else
240 screen = 0;
241#endif
242#ifdef Q_WS_WIN
243 hdc = 0;
244#endif
245}
246
247QFontPrivate::QFontPrivate(const QFontPrivate &other)
248 : request(other.request), engineData(0), dpi(other.dpi), screen(other.screen),
249 rawMode(other.rawMode), underline(other.underline), overline(other.overline),
250 strikeOut(other.strikeOut), kerning(other.kerning),
251 capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
252 letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
253 scFont(other.scFont)
254{
255#ifdef Q_WS_WIN
256 hdc = other.hdc;
257#endif
258 if (scFont && scFont != this)
259 scFont->ref.ref();
260}
261
262QFontPrivate::~QFontPrivate()
263{
264 if (engineData)
265 engineData->ref.deref();
266 engineData = 0;
267 if (scFont && scFont != this)
268 scFont->ref.deref();
269 scFont = 0;
270}
271
272#if !defined(Q_WS_MAC)
273extern QMutex *qt_fontdatabase_mutex();
274
275QFontEngine *QFontPrivate::engineForScript(int script) const
276{
277 QMutexLocker locker(qt_fontdatabase_mutex());
278 if (script >= QUnicodeTables::Inherited)
279 script = QUnicodeTables::Common;
280 if (engineData && engineData->fontCache != QFontCache::instance()) {
281 // throw out engineData that came from a different thread
282 engineData->ref.deref();
283 engineData = 0;
284 }
285 if (!engineData || !engineData->engines[script])
286 QFontDatabase::load(this, script);
287 return engineData->engines[script];
288}
289#else
290QFontEngine *QFontPrivate::engineForScript(int script) const
291{
292 extern QMutex *qt_fontdatabase_mutex();
293 QMutexLocker locker(qt_fontdatabase_mutex());
294 if (script >= QUnicodeTables::Inherited)
295 script = QUnicodeTables::Common;
296 if (engineData && engineData->fontCache != QFontCache::instance()) {
297 // throw out engineData that came from a different thread
298 engineData->ref.deref();
299 engineData = 0;
300 }
301 if (!engineData || !engineData->engine)
302 QFontDatabase::load(this, script);
303 return engineData->engine;
304}
305#endif
306
307void QFontPrivate::alterCharForCapitalization(QChar &c) const {
308 switch (capital) {
309 case QFont::AllUppercase:
310 case QFont::SmallCaps:
311 c = c.toUpper();
312 break;
313 case QFont::AllLowercase:
314 c = c.toLower();
315 break;
316 case QFont::MixedCase:
317 break;
318 }
319}
320
321QFontPrivate *QFontPrivate::smallCapsFontPrivate() const
322{
323 if (scFont)
324 return scFont;
325 QFont font(const_cast<QFontPrivate *>(this));
326 qreal pointSize = font.pointSizeF();
327 if (pointSize > 0)
328 font.setPointSizeF(pointSize * .7);
329 else
330 font.setPixelSize((font.pixelSize() * 7 + 5) / 10);
331 scFont = font.d.data();
332 if (scFont != this)
333 scFont->ref.ref();
334 return scFont;
335}
336
337
338void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
339{
340 Q_ASSERT(other != 0);
341
342 dpi = other->dpi;
343
344 if ((mask & QFont::AllPropertiesResolved) == QFont::AllPropertiesResolved) return;
345
346 // assign the unset-bits with the set-bits of the other font def
347 if (! (mask & QFont::FamilyResolved))
348 request.family = other->request.family;
349
350 if (! (mask & QFont::SizeResolved)) {
351 request.pointSize = other->request.pointSize;
352 request.pixelSize = other->request.pixelSize;
353 }
354
355 if (! (mask & QFont::StyleHintResolved))
356 request.styleHint = other->request.styleHint;
357
358 if (! (mask & QFont::StyleStrategyResolved))
359 request.styleStrategy = other->request.styleStrategy;
360
361 if (! (mask & QFont::WeightResolved))
362 request.weight = other->request.weight;
363
364 if (! (mask & QFont::StyleResolved))
365 request.style = other->request.style;
366
367 if (! (mask & QFont::FixedPitchResolved))
368 request.fixedPitch = other->request.fixedPitch;
369
370 if (! (mask & QFont::StretchResolved))
371 request.stretch = other->request.stretch;
372
373 if (! (mask & QFont::UnderlineResolved))
374 underline = other->underline;
375
376 if (! (mask & QFont::OverlineResolved))
377 overline = other->overline;
378
379 if (! (mask & QFont::StrikeOutResolved))
380 strikeOut = other->strikeOut;
381
382 if (! (mask & QFont::KerningResolved))
383 kerning = other->kerning;
384
385 if (! (mask & QFont::LetterSpacingResolved)) {
386 letterSpacing = other->letterSpacing;
387 letterSpacingIsAbsolute = other->letterSpacingIsAbsolute;
388 }
389 if (! (mask & QFont::WordSpacingResolved))
390 wordSpacing = other->wordSpacing;
391 if (! (mask & QFont::CapitalizationResolved))
392 capital = other->capital;
393}
394
395
396
397
398QFontEngineData::QFontEngineData()
399 : ref(1), fontCache(QFontCache::instance())
400{
401#if !defined(Q_WS_MAC)
402 memset(engines, 0, QUnicodeTables::ScriptCount * sizeof(QFontEngine *));
403#else
404 engine = 0;
405#endif
406}
407
408QFontEngineData::~QFontEngineData()
409{
410#if !defined(Q_WS_MAC)
411 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
412 if (engines[i])
413 engines[i]->ref.deref();
414 engines[i] = 0;
415 }
416#else
417 if (engine)
418 engine->ref.deref();
419 engine = 0;
420#endif // Q_WS_X11 || Q_WS_WIN || Q_WS_MAC
421}
422
423
424
425
426/*!
427 \class QFont
428 \reentrant
429
430 \brief The QFont class specifies a font used for drawing text.
431
432 \ingroup painting
433 \ingroup appearance
434 \ingroup shared
435 \ingroup richtext-processing
436
437
438 When you create a QFont object you specify various attributes that
439 you want the font to have. Qt will use the font with the specified
440 attributes, or if no matching font exists, Qt will use the closest
441 matching installed font. The attributes of the font that is
442 actually used are retrievable from a QFontInfo object. If the
443 window system provides an exact match exactMatch() returns true.
444 Use QFontMetrics to get measurements, e.g. the pixel length of a
445 string using QFontMetrics::width().
446
447 Note that a QApplication instance must exist before a QFont can be
448 used. You can set the application's default font with
449 QApplication::setFont().
450
451 If a chosen font does not include all the characters that
452 need to be displayed, QFont will try to find the characters in the
453 nearest equivalent fonts. When a QPainter draws a character from a
454 font the QFont will report whether or not it has the character; if
455 it does not, QPainter will draw an unfilled square.
456
457 Create QFonts like this:
458
459 \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 0
460
461 The attributes set in the constructor can also be set later, e.g.
462 setFamily(), setPointSize(), setPointSizeFloat(), setWeight() and
463 setItalic(). The remaining attributes must be set after
464 contstruction, e.g. setBold(), setUnderline(), setOverline(),
465 setStrikeOut() and setFixedPitch(). QFontInfo objects should be
466 created \e after the font's attributes have been set. A QFontInfo
467 object will not change, even if you change the font's
468 attributes. The corresponding "get" functions, e.g. family(),
469 pointSize(), etc., return the values that were set, even though
470 the values used may differ. The actual values are available from a
471 QFontInfo object.
472
473 If the requested font family is unavailable you can influence the
474 \link #fontmatching font matching algorithm\endlink by choosing a
475 particular \l{QFont::StyleHint} and \l{QFont::StyleStrategy} with
476 setStyleHint(). The default family (corresponding to the current
477 style hint) is returned by defaultFamily().
478
479 The font-matching algorithm has a lastResortFamily() and
480 lastResortFont() in cases where a suitable match cannot be found.
481 You can provide substitutions for font family names using
482 insertSubstitution() and insertSubstitutions(). Substitutions can
483 be removed with removeSubstitution(). Use substitute() to retrieve
484 a family's first substitute, or the family name itself if it has
485 no substitutes. Use substitutes() to retrieve a list of a family's
486 substitutes (which may be empty).
487
488 Every QFont has a key() which you can use, for example, as the key
489 in a cache or dictionary. If you want to store a user's font
490 preferences you could use QSettings, writing the font information
491 with toString() and reading it back with fromString(). The
492 operator<<() and operator>>() functions are also available, but
493 they work on a data stream.
494
495 It is possible to set the height of characters shown on the screen
496 to a specified number of pixels with setPixelSize(); however using
497 setPointSize() has a similar effect and provides device
498 independence.
499
500 In X11 you can set a font using its system
501 specific name with setRawName().
502
503 Loading fonts can be expensive, especially on X11. QFont contains
504 extensive optimizations to make the copying of QFont objects fast,
505 and to cache the results of the slow window system functions it
506 depends upon.
507
508 \target fontmatching
509 The font matching algorithm works as follows:
510 \list 1
511 \o The specified font family is searched for.
512 \o If not found, the styleHint() is used to select a replacement
513 family.
514 \o Each replacement font family is searched for.
515 \o If none of these are found or there was no styleHint(), "helvetica"
516 will be searched for.
517 \o If "helvetica" isn't found Qt will try the lastResortFamily().
518 \o If the lastResortFamily() isn't found Qt will try the
519 lastResortFont() which will always return a name of some kind.
520 \endlist
521
522 Note that the actual font matching algorithm varies from platform to platform.
523
524 In Windows a request for the "Courier" font is automatically changed to
525 "Courier New", an improved version of Courier that allows for smooth scaling.
526 The older "Courier" bitmap font can be selected by setting the PreferBitmap
527 style strategy (see setStyleStrategy()).
528
529 Once a font is found, the remaining attributes are matched in order of
530 priority:
531 \list 1
532 \o fixedPitch()
533 \o pointSize() (see below)
534 \o weight()
535 \o style()
536 \endlist
537
538 If you have a font which matches on family, even if none of the
539 other attributes match, this font will be chosen in preference to
540 a font which doesn't match on family but which does match on the
541 other attributes. This is because font family is the dominant
542 search criteria.
543
544 The point size is defined to match if it is within 20% of the
545 requested point size. When several fonts match and are only
546 distinguished by point size, the font with the closest point size
547 to the one requested will be chosen.
548
549 The actual family, font size, weight and other font attributes
550 used for drawing text will depend on what's available for the
551 chosen family under the window system. A QFontInfo object can be
552 used to determine the actual values used for drawing the text.
553
554 Examples:
555
556 \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 1
557 If you had both an Adobe and a Cronyx Helvetica, you might get
558 either.
559
560 \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 2
561
562 You can specify the foundry you want in the family name. The font f
563 in the above example will be set to "Helvetica
564 [Cronyx]".
565
566 To determine the attributes of the font actually used in the window
567 system, use a QFontInfo object, e.g.
568
569 \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 3
570
571 To find out font metrics use a QFontMetrics object, e.g.
572
573 \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 4
574
575 For more general information on fonts, see the
576 \link http://nwalsh.com/comp.fonts/FAQ/ comp.fonts FAQ.\endlink
577 Information on encodings can be found from
578 \link http://czyborra.com/ Roman Czyborra's\endlink page.
579
580 \sa QFontComboBox, QFontMetrics, QFontInfo, QFontDatabase, {Character Map Example}
581*/
582
583/*!
584 \internal
585 \enum QFont::ResolveProperties
586
587 This enum describes the properties of a QFont that can be set on a font
588 individually and then considered resolved.
589
590 \value FamilyResolved
591 \value SizeResolved
592 \value StyleHintResolved
593 \value StyleStrategyResolved
594 \value WeightResolved
595 \value StyleResolved
596 \value UnderlineResolved
597 \value OverlineResolved
598 \value StrikeOutResolved
599 \value FixedPitchResolved
600 \value StretchResolved
601 \value KerningResolved
602 \value CapitalizationResolved
603 \value LetterSpacingResolved
604 \value WordSpacingResolved
605 \value CompletelyResolved
606*/
607
608/*!
609 \enum QFont::Style
610
611 This enum describes the different styles of glyphs that are used to
612 display text.
613
614 \value StyleNormal Normal glyphs used in unstyled text.
615 \value StyleItalic Italic glyphs that are specifically designed for
616 the purpose of representing italicized text.
617 \value StyleOblique Glyphs with an italic appearance that are typically
618 based on the unstyled glyphs, but are not fine-tuned
619 for the purpose of representing italicized text.
620
621 \sa Weight
622*/
623
624/*!
625 \fn Qt::HANDLE QFont::handle() const
626
627 Returns the window system handle to the font, for low-level
628 access. Using this function is \e not portable.
629*/
630
631/*!
632 \fn FT_Face QFont::freetypeFace() const
633
634 Returns the handle to the primary FreeType face of the font. If font merging is not disabled a
635 QFont can contain several physical fonts.
636
637 Returns 0 if the font does not contain a FreeType face.
638
639 \note This function is only available on platforms that provide the FreeType library;
640 i.e., X11 and some Embedded Linux platforms.
641*/
642
643/*!
644 \fn QString QFont::rawName() const
645
646 Returns the name of the font within the underlying window system.
647
648 On X11, this function will return an empty string if Qt is built with
649 FontConfig support; otherwise the XLFD (X Logical Font Description) is
650 returned.
651
652 Using the return value of this function is usually \e not \e
653 portable.
654
655 \sa setRawName()
656*/
657
658/*!
659 \fn void QFont::setRawName(const QString &name)
660
661 Sets a font by its system specific name. The function is
662 particularly useful under X, where system font settings (for
663 example X resources) are usually available in XLFD (X Logical Font
664 Description) form only. You can pass an XLFD as \a name to this
665 function.
666
667 A font set with setRawName() is still a full-featured QFont. It can
668 be queried (for example with italic()) or modified (for example with
669 setItalic()) and is therefore also suitable for rendering rich text.
670
671 If Qt's internal font database cannot resolve the raw name, the
672 font becomes a raw font with \a name as its family.
673
674 Note that the present implementation does not handle wildcards in
675 XLFDs well, and that font aliases (file \c fonts.alias in the font
676 directory on X11) are not supported.
677
678 \sa rawName(), setRawMode(), setFamily()
679*/
680
681/*!
682 \fn QString QFont::lastResortFamily() const
683
684 Returns the "last resort" font family name.
685
686 The current implementation tries a wide variety of common fonts,
687 returning the first one it finds. Is is possible that no family is
688 found in which case an empty string is returned.
689
690 \sa lastResortFont()
691*/
692
693/*!
694 \fn QString QFont::defaultFamily() const
695
696 Returns the family name that corresponds to the current style
697 hint.
698
699 \sa StyleHint styleHint() setStyleHint()
700*/
701
702/*!
703 \fn QString QFont::lastResortFont() const
704
705 Returns a "last resort" font name for the font matching algorithm.
706 This is used if the last resort family is not available. It will
707 always return a name, if necessary returning something like
708 "fixed" or "system".
709
710 The current implementation tries a wide variety of common fonts,
711 returning the first one it finds. The implementation may change
712 at any time, but this function will always return a string
713 containing something.
714
715 It is theoretically possible that there really isn't a
716 lastResortFont() in which case Qt will abort with an error
717 message. We have not been able to identify a case where this
718 happens. Please \link bughowto.html report it as a bug\endlink if
719 it does, preferably with a list of the fonts you have installed.
720
721 \sa lastResortFamily() rawName()
722*/
723
724/*!
725 Constructs a font from \a font for use on the paint device \a pd.
726*/
727QFont::QFont(const QFont &font, QPaintDevice *pd)
728 : resolve_mask(font.resolve_mask)
729{
730 Q_ASSERT(pd != 0);
731 int dpi = pd->logicalDpiY();
732#ifdef Q_WS_X11
733 const QX11Info *info = qt_x11Info(pd);
734 int screen = info ? info->screen() : 0;
735#else
736 const int screen = 0;
737#endif
738 if (font.d->dpi != dpi || font.d->screen != screen ) {
739 d = new QFontPrivate(*font.d);
740 d->dpi = dpi;
741 d->screen = screen;
742 } else {
743 d = font.d.data();
744 }
745#ifdef Q_WS_WIN
746 if (pd->devType() == QInternal::Printer && pd->getDC())
747 d->hdc = pd->getDC();
748#endif
749}
750
751/*!
752 \internal
753*/
754QFont::QFont(QFontPrivate *data)
755 : d(data), resolve_mask(QFont::AllPropertiesResolved)
756{
757}
758
759/*! \internal
760 Detaches the font object from common font data.
761*/
762void QFont::detach()
763{
764 if (d->ref == 1) {
765 if (d->engineData)
766 d->engineData->ref.deref();
767 d->engineData = 0;
768 if (d->scFont && d->scFont != d.data())
769 d->scFont->ref.deref();
770 d->scFont = 0;
771 return;
772 }
773
774 d.detach();
775}
776
777/*!
778 Constructs a font object that uses the application's default font.
779
780 \sa QApplication::setFont(), QApplication::font()
781*/
782QFont::QFont()
783 : d(QApplication::font().d.data()), resolve_mask(0)
784{
785}
786
787/*!
788 Constructs a font object with the specified \a family, \a
789 pointSize, \a weight and \a italic settings.
790
791 If \a pointSize is zero or negative, the point size of the font
792 is set to a system-dependent default value. Generally, this is
793 12 points, except on Symbian where it is 7 points.
794
795 The \a family name may optionally also include a foundry name,
796 e.g. "Helvetica [Cronyx]". If the \a family is
797 available from more than one foundry and the foundry isn't
798 specified, an arbitrary foundry is chosen. If the family isn't
799 available a family will be set using the \l{QFont}{font matching}
800 algorithm.
801
802 \sa Weight, setFamily(), setPointSize(), setWeight(), setItalic(),
803 setStyleHint() QApplication::font()
804*/
805QFont::QFont(const QString &family, int pointSize, int weight, bool italic)
806 : d(new QFontPrivate()), resolve_mask(QFont::FamilyResolved)
807{
808 if (pointSize <= 0) {
809#ifdef Q_OS_SYMBIAN
810 pointSize = 7;
811#else
812 pointSize = 12;
813#endif
814 } else {
815 resolve_mask |= QFont::SizeResolved;
816 }
817
818 if (weight < 0) {
819 weight = Normal;
820 } else {
821 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
822 }
823
824 if (italic)
825 resolve_mask |= QFont::StyleResolved;
826
827 d->request.family = family;
828 d->request.pointSize = qreal(pointSize);
829 d->request.pixelSize = -1;
830 d->request.weight = weight;
831 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
832}
833
834/*!
835 Constructs a font that is a copy of \a font.
836*/
837QFont::QFont(const QFont &font)
838 : d(font.d.data()), resolve_mask(font.resolve_mask)
839{
840}
841
842/*!
843 Destroys the font object and frees all allocated resources.
844*/
845QFont::~QFont()
846{
847}
848
849/*!
850 Assigns \a font to this font and returns a reference to it.
851*/
852QFont &QFont::operator=(const QFont &font)
853{
854 d = font.d.data();
855 resolve_mask = font.resolve_mask;
856 return *this;
857}
858
859/*!
860 Returns the requested font family name, i.e. the name set in the
861 constructor or the last setFont() call.
862
863 \sa setFamily() substitutes() substitute()
864*/
865QString QFont::family() const
866{
867 return d->request.family;
868}
869
870/*!
871 Sets the family name of the font. The name is case insensitive and
872 may include a foundry name.
873
874 The \a family name may optionally also include a foundry name,
875 e.g. "Helvetica [Cronyx]". If the \a family is
876 available from more than one foundry and the foundry isn't
877 specified, an arbitrary foundry is chosen. If the family isn't
878 available a family will be set using the \l{QFont}{font matching}
879 algorithm.
880
881 \sa family(), setStyleHint(), QFontInfo
882*/
883void QFont::setFamily(const QString &family)
884{
885 detach();
886
887 d->request.family = family;
888#if defined(Q_WS_X11)
889 d->request.addStyle.clear();
890#endif // Q_WS_X11
891
892 resolve_mask |= QFont::FamilyResolved;
893}
894
895/*!
896 Returns the point size of the font. Returns -1 if the font size
897 was specified in pixels.
898
899 \sa setPointSize() pointSizeF()
900*/
901int QFont::pointSize() const
902{
903 return qRound(d->request.pointSize);
904}
905
906/*!
907 Sets the point size to \a pointSize. The point size must be
908 greater than zero.
909
910 \sa pointSize() setPointSizeF()
911*/
912void QFont::setPointSize(int pointSize)
913{
914 if (pointSize <= 0) {
915 qWarning("QFont::setPointSize: Point size <= 0 (%d), must be greater than 0", pointSize);
916 return;
917 }
918
919 detach();
920
921 d->request.pointSize = qreal(pointSize);
922 d->request.pixelSize = -1;
923
924 resolve_mask |= QFont::SizeResolved;
925}
926
927/*!
928 Sets the point size to \a pointSize. The point size must be
929 greater than zero. The requested precision may not be achieved on
930 all platforms.
931
932 \sa pointSizeF() setPointSize() setPixelSize()
933*/
934void QFont::setPointSizeF(qreal pointSize)
935{
936 if (pointSize <= 0) {
937 qWarning("QFont::setPointSizeF: Point size <= 0 (%f), must be greater than 0", pointSize);
938 return;
939 }
940
941 detach();
942
943 d->request.pointSize = pointSize;
944 d->request.pixelSize = -1;
945
946 resolve_mask |= QFont::SizeResolved;
947}
948
949/*!
950 Returns the point size of the font. Returns -1 if the font size was
951 specified in pixels.
952
953 \sa pointSize() setPointSizeF() pixelSize() QFontInfo::pointSize() QFontInfo::pixelSize()
954*/
955qreal QFont::pointSizeF() const
956{
957 return d->request.pointSize;
958}
959
960/*!
961 Sets the font size to \a pixelSize pixels.
962
963 Using this function makes the font device dependent. Use
964 setPointSize() or setPointSizeF() to set the size of the font
965 in a device independent manner.
966
967 \sa pixelSize()
968*/
969void QFont::setPixelSize(int pixelSize)
970{
971 if (pixelSize <= 0) {
972 qWarning("QFont::setPixelSize: Pixel size <= 0 (%d)", pixelSize);
973 return;
974 }
975
976 detach();
977
978 d->request.pixelSize = pixelSize;
979 d->request.pointSize = -1;
980
981 resolve_mask |= QFont::SizeResolved;
982}
983
984/*!
985 Returns the pixel size of the font if it was set with
986 setPixelSize(). Returns -1 if the size was set with setPointSize()
987 or setPointSizeF().
988
989 \sa setPixelSize() pointSize() QFontInfo::pointSize() QFontInfo::pixelSize()
990*/
991int QFont::pixelSize() const
992{
993 return d->request.pixelSize;
994}
995
996#ifdef QT3_SUPPORT
997/*! \obsolete
998
999 Sets the logical pixel height of font characters when shown on
1000 the screen to \a pixelSize.
1001*/
1002void QFont::setPixelSizeFloat(qreal pixelSize)
1003{
1004 setPixelSize((int)pixelSize);
1005}
1006#endif
1007
1008/*!
1009 \fn bool QFont::italic() const
1010
1011 Returns true if the style() of the font is not QFont::StyleNormal
1012
1013 \sa setItalic() style()
1014*/
1015
1016/*!
1017 \fn void QFont::setItalic(bool enable)
1018
1019 Sets the style() of the font to QFont::StyleItalic if \a enable is true;
1020 otherwise the style is set to QFont::StyleNormal.
1021
1022 \sa italic() QFontInfo
1023*/
1024
1025/*!
1026 Returns the style of the font.
1027
1028 \sa setStyle()
1029*/
1030QFont::Style QFont::style() const
1031{
1032 return (QFont::Style)d->request.style;
1033}
1034
1035
1036/*!
1037 Sets the style of the font to \a style.
1038
1039 \sa italic(), QFontInfo
1040*/
1041void QFont::setStyle(Style style)
1042{
1043 detach();
1044
1045 d->request.style = style;
1046 resolve_mask |= QFont::StyleResolved;
1047}
1048
1049/*!
1050 Returns the weight of the font which is one of the enumerated
1051 values from \l{QFont::Weight}.
1052
1053 \sa setWeight(), Weight, QFontInfo
1054*/
1055int QFont::weight() const
1056{
1057 return d->request.weight;
1058}
1059
1060/*!
1061 \enum QFont::Weight
1062
1063 Qt uses a weighting scale from 0 to 99 similar to, but not the
1064 same as, the scales used in Windows or CSS. A weight of 0 is
1065 ultralight, whilst 99 will be an extremely black.
1066
1067 This enum contains the predefined font weights:
1068
1069 \value Light 25
1070 \value Normal 50
1071 \value DemiBold 63
1072 \value Bold 75
1073 \value Black 87
1074*/
1075
1076/*!
1077 Sets the weight the font to \a weight, which should be a value
1078 from the \l QFont::Weight enumeration.
1079
1080 \sa weight(), QFontInfo
1081*/
1082void QFont::setWeight(int weight)
1083{
1084 Q_ASSERT_X(weight >= 0 && weight <= 99, "QFont::setWeight", "Weight must be between 0 and 99");
1085
1086 detach();
1087
1088 d->request.weight = weight;
1089 resolve_mask |= QFont::WeightResolved;
1090}
1091
1092/*!
1093 \fn bool QFont::bold() const
1094
1095 Returns true if weight() is a value greater than \link Weight
1096 QFont::Normal \endlink; otherwise returns false.
1097
1098 \sa weight(), setBold(), QFontInfo::bold()
1099*/
1100
1101/*!
1102 \fn void QFont::setBold(bool enable)
1103
1104 If \a enable is true sets the font's weight to \link Weight
1105 QFont::Bold \endlink; otherwise sets the weight to \link Weight
1106 QFont::Normal\endlink.
1107
1108 For finer boldness control use setWeight().
1109
1110 \sa bold(), setWeight()
1111*/
1112
1113/*!
1114 Returns true if underline has been set; otherwise returns false.
1115
1116 \sa setUnderline()
1117*/
1118bool QFont::underline() const
1119{
1120 return d->underline;
1121}
1122
1123/*!
1124 If \a enable is true, sets underline on; otherwise sets underline
1125 off.
1126
1127 \sa underline(), QFontInfo
1128*/
1129void QFont::setUnderline(bool enable)
1130{
1131 detach();
1132
1133 d->underline = enable;
1134 resolve_mask |= QFont::UnderlineResolved;
1135}
1136
1137/*!
1138 Returns true if overline has been set; otherwise returns false.
1139
1140 \sa setOverline()
1141*/
1142bool QFont::overline() const
1143{
1144 return d->overline;
1145}
1146
1147/*!
1148 If \a enable is true, sets overline on; otherwise sets overline off.
1149
1150 \sa overline(), QFontInfo
1151*/
1152void QFont::setOverline(bool enable)
1153{
1154 detach();
1155
1156 d->overline = enable;
1157 resolve_mask |= QFont::OverlineResolved;
1158}
1159
1160/*!
1161 Returns true if strikeout has been set; otherwise returns false.
1162
1163 \sa setStrikeOut()
1164*/
1165bool QFont::strikeOut() const
1166{
1167 return d->strikeOut;
1168}
1169
1170/*!
1171 If \a enable is true, sets strikeout on; otherwise sets strikeout
1172 off.
1173
1174 \sa strikeOut(), QFontInfo
1175*/
1176void QFont::setStrikeOut(bool enable)
1177{
1178 detach();
1179
1180 d->strikeOut = enable;
1181 resolve_mask |= QFont::StrikeOutResolved;
1182}
1183
1184/*!
1185 Returns true if fixed pitch has been set; otherwise returns false.
1186
1187 \sa setFixedPitch(), QFontInfo::fixedPitch()
1188*/
1189bool QFont::fixedPitch() const
1190{
1191 return d->request.fixedPitch;
1192}
1193
1194/*!
1195 If \a enable is true, sets fixed pitch on; otherwise sets fixed
1196 pitch off.
1197
1198 \sa fixedPitch(), QFontInfo
1199*/
1200void QFont::setFixedPitch(bool enable)
1201{
1202 detach();
1203
1204 d->request.fixedPitch = enable;
1205 d->request.ignorePitch = false;
1206 resolve_mask |= QFont::FixedPitchResolved;
1207}
1208
1209/*!
1210 Returns true if kerning should be used when drawing text with this font.
1211
1212 \sa setKerning()
1213*/
1214bool QFont::kerning() const
1215{
1216 return d->kerning;
1217}
1218
1219/*!
1220 Enables kerning for this font if \a enable is true; otherwise
1221 disables it. By default, kerning is enabled.
1222
1223 When kerning is enabled, glyph metrics do not add up anymore,
1224 even for Latin text. In other words, the assumption that
1225 width('a') + width('b') is equal to width("ab") is not
1226 neccesairly true.
1227
1228 \sa kerning(), QFontMetrics
1229*/
1230void QFont::setKerning(bool enable)
1231{
1232 detach();
1233 d->kerning = enable;
1234 resolve_mask |= QFont::KerningResolved;
1235}
1236
1237/*!
1238 Returns the StyleStrategy.
1239
1240 The style strategy affects the \l{QFont}{font matching} algorithm.
1241 See \l QFont::StyleStrategy for the list of available strategies.
1242
1243 \sa setStyleHint() QFont::StyleHint
1244*/
1245QFont::StyleStrategy QFont::styleStrategy() const
1246{
1247 return (StyleStrategy) d->request.styleStrategy;
1248}
1249
1250/*!
1251 Returns the StyleHint.
1252
1253 The style hint affects the \l{QFont}{font matching} algorithm.
1254 See \l QFont::StyleHint for the list of available hints.
1255
1256 \sa setStyleHint(), QFont::StyleStrategy QFontInfo::styleHint()
1257*/
1258QFont::StyleHint QFont::styleHint() const
1259{
1260 return (StyleHint) d->request.styleHint;
1261}
1262
1263/*!
1264 \enum QFont::StyleHint
1265
1266 Style hints are used by the \l{QFont}{font matching} algorithm to
1267 find an appropriate default family if a selected font family is
1268 not available.
1269
1270 \value AnyStyle leaves the font matching algorithm to choose the
1271 family. This is the default.
1272
1273 \value SansSerif the font matcher prefer sans serif fonts.
1274 \value Helvetica is a synonym for \c SansSerif.
1275
1276 \value Serif the font matcher prefers serif fonts.
1277 \value Times is a synonym for \c Serif.
1278
1279 \value TypeWriter the font matcher prefers fixed pitch fonts.
1280 \value Courier a synonym for \c TypeWriter.
1281
1282 \value OldEnglish the font matcher prefers decorative fonts.
1283 \value Decorative is a synonym for \c OldEnglish.
1284
1285 \value System the font matcher prefers system fonts.
1286*/
1287
1288/*!
1289 \enum QFont::StyleStrategy
1290
1291 The style strategy tells the \l{QFont}{font matching} algorithm
1292 what type of fonts should be used to find an appropriate default
1293 family.
1294
1295 The following strategies are available:
1296
1297 \value PreferDefault the default style strategy. It does not prefer
1298 any type of font.
1299 \value PreferBitmap prefers bitmap fonts (as opposed to outline
1300 fonts).
1301 \value PreferDevice prefers device fonts.
1302 \value PreferOutline prefers outline fonts (as opposed to bitmap fonts).
1303 \value ForceOutline forces the use of outline fonts.
1304 \value NoAntialias don't antialias the fonts.
1305 \value PreferAntialias antialias if possible.
1306 \value OpenGLCompatible forces the use of OpenGL compatible
1307 fonts.
1308 \value NoFontMerging If a font does not contain a character requested
1309 to draw then Qt automatically chooses a similar looking for that contains
1310 the character. This flag disables this feature.
1311
1312 Any of these may be OR-ed with one of these flags:
1313
1314 \value PreferMatch prefer an exact match. The font matcher will try to
1315 use the exact font size that has been specified.
1316 \value PreferQuality prefer the best quality font. The font matcher
1317 will use the nearest standard point size that the font
1318 supports.
1319*/
1320
1321/*!
1322 Sets the style hint and strategy to \a hint and \a strategy,
1323 respectively.
1324
1325 If these aren't set explicitly the style hint will default to
1326 \c AnyStyle and the style strategy to \c PreferDefault.
1327
1328 Qt does not support style hints on X11 since this information
1329 is not provided by the window system.
1330
1331 \sa StyleHint, styleHint(), StyleStrategy, styleStrategy(), QFontInfo
1332*/
1333void QFont::setStyleHint(StyleHint hint, StyleStrategy strategy)
1334{
1335 detach();
1336
1337 if ((resolve_mask & (QFont::StyleHintResolved | QFont::StyleStrategyResolved)) &&
1338 (StyleHint) d->request.styleHint == hint &&
1339 (StyleStrategy) d->request.styleStrategy == strategy)
1340 return;
1341
1342 d->request.styleHint = hint;
1343 d->request.styleStrategy = strategy;
1344 resolve_mask |= QFont::StyleHintResolved;
1345 resolve_mask |= QFont::StyleStrategyResolved;
1346
1347#if defined(Q_WS_X11)
1348 d->request.addStyle.clear();
1349#endif // Q_WS_X11
1350}
1351
1352/*!
1353 Sets the style strategy for the font to \a s.
1354
1355 \sa QFont::StyleStrategy
1356*/
1357void QFont::setStyleStrategy(StyleStrategy s)
1358{
1359 detach();
1360
1361 if ((resolve_mask & QFont::StyleStrategyResolved) &&
1362 s == (StyleStrategy)d->request.styleStrategy)
1363 return;
1364
1365 d->request.styleStrategy = s;
1366 resolve_mask |= QFont::StyleStrategyResolved;
1367}
1368
1369
1370/*!
1371 \enum QFont::Stretch
1372
1373 Predefined stretch values that follow the CSS naming convention. The higher
1374 the value, the more stretched the text is.
1375
1376 \value UltraCondensed 50
1377 \value ExtraCondensed 62
1378 \value Condensed 75
1379 \value SemiCondensed 87
1380 \value Unstretched 100
1381 \value SemiExpanded 112
1382 \value Expanded 125
1383 \value ExtraExpanded 150
1384 \value UltraExpanded 200
1385
1386 \sa setStretch() stretch()
1387*/
1388
1389/*!
1390 Returns the stretch factor for the font.
1391
1392 \sa setStretch()
1393 */
1394int QFont::stretch() const
1395{
1396 return d->request.stretch;
1397}
1398
1399/*!
1400 Sets the stretch factor for the font.
1401
1402 The stretch factor changes the width of all characters in the font
1403 by \a factor percent. For example, setting \a factor to 150
1404 results in all characters in the font being 1.5 times (ie. 150%)
1405 wider. The default stretch factor is 100. The minimum stretch
1406 factor is 1, and the maximum stretch factor is 4000.
1407
1408 The stretch factor is only applied to outline fonts. The stretch
1409 factor is ignored for bitmap fonts.
1410
1411 NOTE: QFont cannot stretch XLFD fonts. When loading XLFD fonts on
1412 X11, the stretch factor is matched against a predefined set of
1413 values for the SETWIDTH_NAME field of the XLFD.
1414
1415 \sa stretch() QFont::Stretch
1416*/
1417void QFont::setStretch(int factor)
1418{
1419 if (factor < 1 || factor > 4000) {
1420 qWarning("QFont::setStretch: Parameter '%d' out of range", factor);
1421 return;
1422 }
1423
1424 if ((resolve_mask & QFont::StretchResolved) &&
1425 d->request.stretch == (uint)factor)
1426 return;
1427
1428 detach();
1429
1430 d->request.stretch = (uint)factor;
1431 resolve_mask |= QFont::StretchResolved;
1432}
1433
1434/*!
1435 \enum QFont::SpacingType
1436 \since 4.4
1437
1438 \value PercentageSpacing A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the
1439 spacing after a character by the width of the character itself.
1440 \value AbsoluteSpacing A positive value increases the letter spacing by the corresponding pixels; a negative
1441 value decreases the spacing.
1442*/
1443
1444/*!
1445 \since 4.4
1446 Returns the letter spacing for the font.
1447
1448 \sa setLetterSpacing(), letterSpacingType(), setWordSpacing()
1449 */
1450qreal QFont::letterSpacing() const
1451{
1452 return d->letterSpacing.toReal();
1453}
1454
1455/*!
1456 \since 4.4
1457 Sets the letter spacing for the font to \a spacing and the type
1458 of spacing to \a type.
1459
1460 Letter spacing changes the default spacing between individual
1461 letters in the font. The spacing between the letters can be
1462 made smaller as well as larger.
1463
1464 \sa letterSpacing(), letterSpacingType(), setWordSpacing()
1465*/
1466void QFont::setLetterSpacing(SpacingType type, qreal spacing)
1467{
1468 const QFixed newSpacing = QFixed::fromReal(spacing);
1469 const bool absoluteSpacing = type == AbsoluteSpacing;
1470 if ((resolve_mask & QFont::LetterSpacingResolved) &&
1471 d->letterSpacingIsAbsolute == absoluteSpacing &&
1472 d->letterSpacing == newSpacing)
1473 return;
1474
1475 detach();
1476
1477 d->letterSpacing = newSpacing;
1478 d->letterSpacingIsAbsolute = absoluteSpacing;
1479 resolve_mask |= QFont::LetterSpacingResolved;
1480}
1481
1482/*!
1483 \since 4.4
1484 Returns the spacing type used for letter spacing.
1485
1486 \sa letterSpacing(), setLetterSpacing(), setWordSpacing()
1487*/
1488QFont::SpacingType QFont::letterSpacingType() const
1489{
1490 return d->letterSpacingIsAbsolute ? AbsoluteSpacing : PercentageSpacing;
1491}
1492
1493/*!
1494 \since 4.4
1495 Returns the word spacing for the font.
1496
1497 \sa setWordSpacing(), setLetterSpacing()
1498 */
1499qreal QFont::wordSpacing() const
1500{
1501 return d->wordSpacing.toReal();
1502}
1503
1504/*!
1505 \since 4.4
1506 Sets the word spacing for the font to \a spacing.
1507
1508 Word spacing changes the default spacing between individual
1509 words. A positive value increases the word spacing
1510 by a corresponding amount of pixels, while a negative value
1511 decreases the inter-word spacing accordingly.
1512
1513 Word spacing will not apply to writing systems, where indiviaul
1514 words are not separated by white space.
1515
1516 \sa wordSpacing(), setLetterSpacing()
1517*/
1518void QFont::setWordSpacing(qreal spacing)
1519{
1520 const QFixed newSpacing = QFixed::fromReal(spacing);
1521 if ((resolve_mask & QFont::WordSpacingResolved) &&
1522 d->wordSpacing == newSpacing)
1523 return;
1524
1525 detach();
1526
1527 d->wordSpacing = newSpacing;
1528 resolve_mask |= QFont::WordSpacingResolved;
1529}
1530
1531/*!
1532 \enum QFont::Capitalization
1533 \since 4.4
1534
1535 Rendering option for text this font applies to.
1536
1537
1538 \value MixedCase This is the normal text rendering option where no capitalization change is applied.
1539 \value AllUppercase This alters the text to be rendered in all uppercase type.
1540 \value AllLowercase This alters the text to be rendered in all lowercase type.
1541 \value SmallCaps This alters the text to be rendered in small-caps type.
1542 \value Capitalize This alters the text to be rendered with the first character of each word as an uppercase character.
1543*/
1544
1545/*!
1546 \since 4.4
1547 Sets the capitalization of the text in this font to \a caps.
1548
1549 A font's capitalization makes the text appear in the selected capitalization mode.
1550
1551 \sa capitalization()
1552*/
1553void QFont::setCapitalization(Capitalization caps)
1554{
1555 if ((resolve_mask & QFont::CapitalizationResolved) &&
1556 capitalization() == caps)
1557 return;
1558
1559 detach();
1560
1561 d->capital = caps;
1562 resolve_mask |= QFont::CapitalizationResolved;
1563}
1564
1565/*!
1566 \since 4.4
1567 Returns the current capitalization type of the font.
1568
1569 \sa setCapitalization()
1570*/
1571QFont::Capitalization QFont::capitalization() const
1572{
1573 return static_cast<QFont::Capitalization> (d->capital);
1574}
1575
1576
1577/*!
1578 If \a enable is true, turns raw mode on; otherwise turns raw mode
1579 off. This function only has an effect under X11.
1580
1581 If raw mode is enabled, Qt will search for an X font with a
1582 complete font name matching the family name, ignoring all other
1583 values set for the QFont. If the font name matches several fonts,
1584 Qt will use the first font returned by X. QFontInfo \e cannot be
1585 used to fetch information about a QFont using raw mode (it will
1586 return the values set in the QFont for all parameters, including
1587 the family name).
1588
1589 \warning Do not use raw mode unless you really, really need it! In
1590 most (if not all) cases, setRawName() is a much better choice.
1591
1592 \sa rawMode(), setRawName()
1593*/
1594void QFont::setRawMode(bool enable)
1595{
1596 detach();
1597
1598 if ((bool) d->rawMode == enable) return;
1599
1600 d->rawMode = enable;
1601}
1602
1603/*!
1604 Returns true if a window system font exactly matching the settings
1605 of this font is available.
1606
1607 \sa QFontInfo
1608*/
1609bool QFont::exactMatch() const
1610{
1611 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
1612 Q_ASSERT(engine != 0);
1613 return (d->rawMode
1614 ? engine->type() != QFontEngine::Box
1615 : d->request.exactMatch(engine->fontDef));
1616}
1617
1618/*!
1619 Returns true if this font is equal to \a f; otherwise returns
1620 false.
1621
1622 Two QFonts are considered equal if their font attributes are
1623 equal. If rawMode() is enabled for both fonts, only the family
1624 fields are compared.
1625
1626 \sa operator!=() isCopyOf()
1627*/
1628bool QFont::operator==(const QFont &f) const
1629{
1630 return (f.d == d
1631 || (f.d->request == d->request
1632 && f.d->request.pointSize == d->request.pointSize
1633 && f.d->underline == d->underline
1634 && f.d->overline == d->overline
1635 && f.d->strikeOut == d->strikeOut
1636 && f.d->kerning == d->kerning
1637 && f.d->capital == d->capital
1638 && f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
1639 && f.d->letterSpacing == d->letterSpacing
1640 && f.d->wordSpacing == d->wordSpacing
1641 ));
1642}
1643
1644
1645/*!
1646 Provides an arbitrary comparison of this font and font \a f.
1647 All that is guaranteed is that the operator returns false if both
1648 fonts are equal and that (f1 \< f2) == !(f2 \< f1) if the fonts
1649 are not equal.
1650
1651 This function is useful in some circumstances, for example if you
1652 want to use QFont objects as keys in a QMap.
1653
1654 \sa operator==() operator!=() isCopyOf()
1655*/
1656bool QFont::operator<(const QFont &f) const
1657{
1658 if (f.d == d) return false;
1659 // the < operator for fontdefs ignores point sizes.
1660 QFontDef &r1 = f.d->request;
1661 QFontDef &r2 = d->request;
1662 if (r1.pointSize != r2.pointSize) return r1.pointSize < r2.pointSize;
1663 if (r1.pixelSize != r2.pixelSize) return r1.pixelSize < r2.pixelSize;
1664 if (r1.weight != r2.weight) return r1.weight < r2.weight;
1665 if (r1.style != r2.style) return r1.style < r2.style;
1666 if (r1.stretch != r2.stretch) return r1.stretch < r2.stretch;
1667 if (r1.styleHint != r2.styleHint) return r1.styleHint < r2.styleHint;
1668 if (r1.styleStrategy != r2.styleStrategy) return r1.styleStrategy < r2.styleStrategy;
1669 if (r1.family != r2.family) return r1.family < r2.family;
1670#ifdef Q_WS_X11
1671 if (r1.addStyle != r2.addStyle) return r1.addStyle < r2.addStyle;
1672#endif // Q_WS_X11
1673 if (f.d->capital != d->capital) return f.d->capital < d->capital;
1674
1675 if (f.d->letterSpacingIsAbsolute != d->letterSpacingIsAbsolute) return f.d->letterSpacingIsAbsolute < d->letterSpacingIsAbsolute;
1676 if (f.d->letterSpacing != d->letterSpacing) return f.d->letterSpacing < d->letterSpacing;
1677 if (f.d->wordSpacing != d->wordSpacing) return f.d->wordSpacing < d->wordSpacing;
1678
1679 int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
1680 int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
1681 return f1attrs < f2attrs;
1682}
1683
1684
1685/*!
1686 Returns true if this font is different from \a f; otherwise
1687 returns false.
1688
1689 Two QFonts are considered to be different if their font attributes
1690 are different. If rawMode() is enabled for both fonts, only the
1691 family fields are compared.
1692
1693 \sa operator==()
1694*/
1695bool QFont::operator!=(const QFont &f) const
1696{
1697 return !(operator==(f));
1698}
1699
1700/*!
1701 Returns the font as a QVariant
1702*/
1703QFont::operator QVariant() const
1704{
1705 return QVariant(QVariant::Font, this);
1706}
1707
1708/*!
1709 Returns true if this font and \a f are copies of each other, i.e.
1710 one of them was created as a copy of the other and neither has
1711 been modified since. This is much stricter than equality.
1712
1713 \sa operator=() operator==()
1714*/
1715bool QFont::isCopyOf(const QFont & f) const
1716{
1717 return d == f.d;
1718}
1719
1720/*!
1721 Returns true if raw mode is used for font name matching; otherwise
1722 returns false.
1723
1724 \sa setRawMode() rawName()
1725*/
1726bool QFont::rawMode() const
1727{
1728 return d->rawMode;
1729}
1730
1731/*!
1732 Returns a new QFont that has attributes copied from \a other that
1733 have not been previously set on this font.
1734*/
1735QFont QFont::resolve(const QFont &other) const
1736{
1737 if (*this == other
1738 && (resolve_mask == other.resolve_mask || resolve_mask == 0)
1739 && d->dpi == other.d->dpi) {
1740 QFont o = other;
1741 o.resolve_mask = resolve_mask;
1742 return o;
1743 }
1744
1745 QFont font(*this);
1746 font.detach();
1747 font.d->resolve(resolve_mask, other.d.data());
1748
1749 return font;
1750}
1751
1752/*!
1753 \fn uint QFont::resolve() const
1754 \internal
1755*/
1756
1757/*!
1758 \fn void QFont::resolve(uint mask)
1759 \internal
1760*/
1761
1762#ifdef QT3_SUPPORT
1763
1764/*! \obsolete
1765
1766 Please use QApplication::font() instead.
1767*/
1768QFont QFont::defaultFont()
1769{
1770 return QApplication::font();
1771}
1772
1773/*! \obsolete
1774
1775 Please use QApplication::setFont() instead.
1776*/
1777void QFont::setDefaultFont(const QFont &f)
1778{
1779 QApplication::setFont(f);
1780}
1781
1782/*!
1783 \fn qreal QFont::pointSizeFloat() const
1784 \compat
1785
1786 Use pointSizeF() instead.
1787*/
1788
1789/*!
1790 \fn void QFont::setPointSizeFloat(qreal size)
1791 \compat
1792
1793 Use setPointSizeF() instead.
1794*/
1795#endif
1796
1797
1798
1799
1800/*****************************************************************************
1801 QFont substitution management
1802 *****************************************************************************/
1803
1804typedef QHash<QString, QStringList> QFontSubst;
1805Q_GLOBAL_STATIC(QFontSubst, globalFontSubst)
1806
1807// create substitution dict
1808static void initFontSubst()
1809{
1810 // default substitutions
1811 static const char * const initTbl[] = {
1812
1813#if defined(Q_WS_X11)
1814 "arial", "helvetica",
1815 "times new roman", "times",
1816 "courier new", "courier",
1817 "sans serif", "helvetica",
1818#elif defined(Q_WS_WIN)
1819 "times", "times new roman",
1820 "courier", "courier new",
1821 "helvetica", "arial",
1822 "sans serif", "arial",
1823#endif
1824
1825 0, 0
1826 };
1827
1828 QFontSubst *fontSubst = globalFontSubst();
1829 Q_ASSERT(fontSubst != 0);
1830 if (!fontSubst->isEmpty())
1831 return;
1832#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)
1833 if (X11->has_fontconfig)
1834 return;
1835#endif
1836
1837 for (int i=0; initTbl[i] != 0; i += 2) {
1838 QStringList &list = (*fontSubst)[QString::fromLatin1(initTbl[i])];
1839 list.append(QString::fromLatin1(initTbl[i+1]));
1840 }
1841}
1842
1843/*!
1844 Returns the first family name to be used whenever \a familyName is
1845 specified. The lookup is case insensitive.
1846
1847 If there is no substitution for \a familyName, \a familyName is
1848 returned.
1849
1850 To obtain a list of substitutions use substitutes().
1851
1852 \sa setFamily() insertSubstitutions() insertSubstitution() removeSubstitution()
1853*/
1854QString QFont::substitute(const QString &familyName)
1855{
1856 initFontSubst();
1857
1858 QFontSubst *fontSubst = globalFontSubst();
1859 Q_ASSERT(fontSubst != 0);
1860 QFontSubst::ConstIterator it = fontSubst->constFind(familyName.toLower());
1861 if (it != fontSubst->constEnd() && !(*it).isEmpty())
1862 return (*it).first();
1863
1864 return familyName;
1865}
1866
1867
1868/*!
1869 Returns a list of family names to be used whenever \a familyName
1870 is specified. The lookup is case insensitive.
1871
1872 If there is no substitution for \a familyName, an empty list is
1873 returned.
1874
1875 \sa substitute() insertSubstitutions() insertSubstitution() removeSubstitution()
1876 */
1877QStringList QFont::substitutes(const QString &familyName)
1878{
1879 initFontSubst();
1880
1881 QFontSubst *fontSubst = globalFontSubst();
1882 Q_ASSERT(fontSubst != 0);
1883 return fontSubst->value(familyName.toLower(), QStringList());
1884}
1885
1886
1887/*!
1888 Inserts \a substituteName into the substitution
1889 table for the family \a familyName.
1890
1891 \sa insertSubstitutions() removeSubstitution() substitutions() substitute() substitutes()
1892*/
1893void QFont::insertSubstitution(const QString &familyName,
1894 const QString &substituteName)
1895{
1896 initFontSubst();
1897
1898 QFontSubst *fontSubst = globalFontSubst();
1899 Q_ASSERT(fontSubst != 0);
1900 QStringList &list = (*fontSubst)[familyName.toLower()];
1901 QString s = substituteName.toLower();
1902 if (!list.contains(s))
1903 list.append(s);
1904}
1905
1906
1907/*!
1908 Inserts the list of families \a substituteNames into the
1909 substitution list for \a familyName.
1910
1911 \sa insertSubstitution(), removeSubstitution(), substitutions(), substitute()
1912*/
1913void QFont::insertSubstitutions(const QString &familyName,
1914 const QStringList &substituteNames)
1915{
1916 initFontSubst();
1917
1918 QFontSubst *fontSubst = globalFontSubst();
1919 Q_ASSERT(fontSubst != 0);
1920 QStringList &list = (*fontSubst)[familyName.toLower()];
1921 QStringList::ConstIterator it = substituteNames.constBegin();
1922 while (it != substituteNames.constEnd()) {
1923 QString s = (*it).toLower();
1924 if (!list.contains(s))
1925 list.append(s);
1926 it++;
1927 }
1928}
1929
1930/*! \fn void QFont::initialize()
1931 \internal
1932
1933 Internal function that initializes the font system. The font cache
1934 and font dict do not alloc the keys. The key is a QString which is
1935 shared between QFontPrivate and QXFontName.
1936*/
1937
1938/*! \fn void QFont::cleanup()
1939 \internal
1940
1941 Internal function that cleans up the font system.
1942*/
1943
1944// ### mark: should be called removeSubstitutions()
1945/*!
1946 Removes all the substitutions for \a familyName.
1947
1948 \sa insertSubstitutions(), insertSubstitution(), substitutions(), substitute()
1949*/
1950void QFont::removeSubstitution(const QString &familyName)
1951{ // ### function name should be removeSubstitutions() or
1952 // ### removeSubstitutionList()
1953 initFontSubst();
1954
1955 QFontSubst *fontSubst = globalFontSubst();
1956 Q_ASSERT(fontSubst != 0);
1957 fontSubst->remove(familyName.toLower());
1958}
1959
1960
1961/*!
1962 Returns a sorted list of substituted family names.
1963
1964 \sa insertSubstitution(), removeSubstitution(), substitute()
1965*/
1966QStringList QFont::substitutions()
1967{
1968 initFontSubst();
1969
1970 QFontSubst *fontSubst = globalFontSubst();
1971 Q_ASSERT(fontSubst != 0);
1972 QStringList ret;
1973 QFontSubst::ConstIterator it = fontSubst->constBegin();
1974
1975 while (it != fontSubst->constEnd()) {
1976 ret.append(it.key());
1977 ++it;
1978 }
1979
1980 ret.sort();
1981 return ret;
1982}
1983
1984
1985/* \internal
1986 Internal function. Converts boolean font settings to an unsigned
1987 8-bit number. Used for serialization etc.
1988*/
1989static quint8 get_font_bits(int version, const QFontPrivate *f)
1990{
1991 Q_ASSERT(f != 0);
1992 quint8 bits = 0;
1993 if (f->request.style)
1994 bits |= 0x01;
1995 if (f->underline)
1996 bits |= 0x02;
1997 if (f->overline)
1998 bits |= 0x40;
1999 if (f->strikeOut)
2000 bits |= 0x04;
2001 if (f->request.fixedPitch)
2002 bits |= 0x08;
2003 // if (f.hintSetByUser)
2004 // bits |= 0x10;
2005 if (f->rawMode)
2006 bits |= 0x20;
2007 if (version >= QDataStream::Qt_4_0) {
2008 if (f->kerning)
2009 bits |= 0x10;
2010 }
2011 if (f->request.style == QFont::StyleOblique)
2012 bits |= 0x80;
2013 return bits;
2014}
2015
2016static quint8 get_extended_font_bits(const QFontPrivate *f)
2017{
2018 Q_ASSERT(f != 0);
2019 quint8 bits = 0;
2020 if (f->request.ignorePitch)
2021 bits |= 0x01;
2022 if (f->letterSpacingIsAbsolute)
2023 bits |= 0x02;
2024 return bits;
2025}
2026
2027#ifndef QT_NO_DATASTREAM
2028
2029/* \internal
2030 Internal function. Sets boolean font settings from an unsigned
2031 8-bit number. Used for serialization etc.
2032*/
2033static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
2034{
2035 Q_ASSERT(f != 0);
2036 f->request.style = (bits & 0x01) != 0 ? QFont::StyleItalic : QFont::StyleNormal;
2037 f->underline = (bits & 0x02) != 0;
2038 f->overline = (bits & 0x40) != 0;
2039 f->strikeOut = (bits & 0x04) != 0;
2040 f->request.fixedPitch = (bits & 0x08) != 0;
2041 // f->hintSetByUser = (bits & 0x10) != 0;
2042 f->rawMode = (bits & 0x20) != 0;
2043 if (version >= QDataStream::Qt_4_0)
2044 f->kerning = (bits & 0x10) != 0;
2045 if ((bits & 0x80) != 0)
2046 f->request.style = QFont::StyleOblique;
2047}
2048
2049static void set_extended_font_bits(quint8 bits, QFontPrivate *f)
2050{
2051 Q_ASSERT(f != 0);
2052 f->request.ignorePitch = (bits & 0x01) != 0;
2053 f->letterSpacingIsAbsolute = (bits & 0x02) != 0;
2054}
2055#endif
2056
2057
2058/*!
2059 Returns the font's key, a textual representation of a font. It is
2060 typically used as the key for a cache or dictionary of fonts.
2061
2062 \sa QMap
2063*/
2064QString QFont::key() const
2065{
2066 return toString();
2067}
2068
2069/*!
2070 Returns a description of the font. The description is a
2071 comma-separated list of the attributes, perfectly suited for use
2072 in QSettings.
2073
2074 \sa fromString()
2075 */
2076QString QFont::toString() const
2077{
2078 const QChar comma(QLatin1Char(','));
2079 return family() + comma +
2080 QString::number( pointSizeF()) + comma +
2081 QString::number( pixelSize()) + comma +
2082 QString::number((int) styleHint()) + comma +
2083 QString::number( weight()) + comma +
2084 QString::number((int) style()) + comma +
2085 QString::number((int) underline()) + comma +
2086 QString::number((int) strikeOut()) + comma +
2087 QString::number((int)fixedPitch()) + comma +
2088 QString::number((int) rawMode());
2089}
2090
2091
2092/*!
2093 Sets this font to match the description \a descrip. The description
2094 is a comma-separated list of the font attributes, as returned by
2095 toString().
2096
2097 \sa toString()
2098 */
2099bool QFont::fromString(const QString &descrip)
2100{
2101 QStringList l(descrip.split(QLatin1Char(',')));
2102
2103 int count = l.count();
2104 if (!count || (count > 2 && count < 9) || count > 11) {
2105 qWarning("QFont::fromString: Invalid description '%s'",
2106 descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
2107 return false;
2108 }
2109
2110 setFamily(l[0]);
2111 if (count > 1 && l[1].toDouble() > 0.0)
2112 setPointSizeF(l[1].toDouble());
2113 if (count == 9) {
2114 setStyleHint((StyleHint) l[2].toInt());
2115 setWeight(qMax(qMin(99, l[3].toInt()), 0));
2116 setItalic(l[4].toInt());
2117 setUnderline(l[5].toInt());
2118 setStrikeOut(l[6].toInt());
2119 setFixedPitch(l[7].toInt());
2120 setRawMode(l[8].toInt());
2121 } else if (count == 10) {
2122 if (l[2].toInt() > 0)
2123 setPixelSize(l[2].toInt());
2124 setStyleHint((StyleHint) l[3].toInt());
2125 setWeight(qMax(qMin(99, l[4].toInt()), 0));
2126 setStyle((QFont::Style)l[5].toInt());
2127 setUnderline(l[6].toInt());
2128 setStrikeOut(l[7].toInt());
2129 setFixedPitch(l[8].toInt());
2130 setRawMode(l[9].toInt());
2131 }
2132 if (count >= 9 && !d->request.fixedPitch) // assume 'false' fixedPitch equals default
2133 d->request.ignorePitch = true;
2134
2135 return true;
2136}
2137
2138#if !defined(Q_WS_QWS)
2139/*! \internal
2140
2141 Internal function that dumps font cache statistics.
2142*/
2143void QFont::cacheStatistics()
2144{
2145
2146
2147}
2148#endif // !Q_WS_QWS
2149
2150
2151
2152/*****************************************************************************
2153 QFont stream functions
2154 *****************************************************************************/
2155#ifndef QT_NO_DATASTREAM
2156
2157/*!
2158 \relates QFont
2159
2160 Writes the font \a font to the data stream \a s. (toString()
2161 writes to a text stream.)
2162
2163 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
2164*/
2165QDataStream &operator<<(QDataStream &s, const QFont &font)
2166{
2167 if (s.version() == 1) {
2168 s << font.d->request.family.toLatin1();
2169 } else {
2170 s << font.d->request.family;
2171 }
2172
2173 if (s.version() >= QDataStream::Qt_4_0) {
2174 // 4.0
2175 double pointSize = font.d->request.pointSize;
2176 qint32 pixelSize = font.d->request.pixelSize;
2177 s << pointSize;
2178 s << pixelSize;
2179 } else if (s.version() <= 3) {
2180 qint16 pointSize = (qint16) (font.d->request.pointSize * 10);
2181 if (pointSize < 0) {
2182#ifdef Q_WS_X11
2183 pointSize = (qint16)(font.d->request.pixelSize*720/QX11Info::appDpiY());
2184#else
2185 pointSize = (qint16)QFontInfo(font).pointSize() * 10;
2186#endif
2187 }
2188 s << pointSize;
2189 } else {
2190 s << (qint16) (font.d->request.pointSize * 10);
2191 s << (qint16) font.d->request.pixelSize;
2192 }
2193
2194 s << (quint8) font.d->request.styleHint;
2195 if (s.version() >= QDataStream::Qt_3_1)
2196 s << (quint8) font.d->request.styleStrategy;
2197 s << (quint8) 0
2198 << (quint8) font.d->request.weight
2199 << get_font_bits(s.version(), font.d.data());
2200 if (s.version() >= QDataStream::Qt_4_3)
2201 s << (quint16)font.d->request.stretch;
2202 if (s.version() >= QDataStream::Qt_4_4)
2203 s << get_extended_font_bits(font.d.data());
2204 if (s.version() >= QDataStream::Qt_4_5) {
2205 s << font.d->letterSpacing.value();
2206 s << font.d->wordSpacing.value();
2207 }
2208 return s;
2209}
2210
2211
2212/*!
2213 \relates QFont
2214
2215 Reads the font \a font from the data stream \a s. (fromString()
2216 reads from a text stream.)
2217
2218 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
2219*/
2220QDataStream &operator>>(QDataStream &s, QFont &font)
2221{
2222 font.d = new QFontPrivate;
2223 font.resolve_mask = QFont::AllPropertiesResolved;
2224
2225 quint8 styleHint, styleStrategy = QFont::PreferDefault, charSet, weight, bits;
2226
2227 if (s.version() == 1) {
2228 QByteArray fam;
2229 s >> fam;
2230 font.d->request.family = QString::fromLatin1(fam);
2231 } else {
2232 s >> font.d->request.family;
2233 }
2234
2235 if (s.version() >= QDataStream::Qt_4_0) {
2236 // 4.0
2237 double pointSize;
2238 qint32 pixelSize;
2239 s >> pointSize;
2240 s >> pixelSize;
2241 font.d->request.pointSize = qreal(pointSize);
2242 font.d->request.pixelSize = pixelSize;
2243 } else {
2244 qint16 pointSize, pixelSize = -1;
2245 s >> pointSize;
2246 if (s.version() >= 4)
2247 s >> pixelSize;
2248 font.d->request.pointSize = qreal(pointSize / 10.);
2249 font.d->request.pixelSize = pixelSize;
2250 }
2251 s >> styleHint;
2252 if (s.version() >= QDataStream::Qt_3_1)
2253 s >> styleStrategy;
2254
2255 s >> charSet;
2256 s >> weight;
2257 s >> bits;
2258
2259 font.d->request.styleHint = styleHint;
2260 font.d->request.styleStrategy = styleStrategy;
2261 font.d->request.weight = weight;
2262
2263 set_font_bits(s.version(), bits, font.d.data());
2264
2265 if (s.version() >= QDataStream::Qt_4_3) {
2266 quint16 stretch;
2267 s >> stretch;
2268 font.d->request.stretch = stretch;
2269 }
2270
2271 if (s.version() >= QDataStream::Qt_4_4) {
2272 quint8 extendedBits;
2273 s >> extendedBits;
2274 set_extended_font_bits(extendedBits, font.d.data());
2275 }
2276 if (s.version() >= QDataStream::Qt_4_5) {
2277 int value;
2278 s >> value;
2279 font.d->letterSpacing.setValue(value);
2280 s >> value;
2281 font.d->wordSpacing.setValue(value);
2282 }
2283
2284 return s;
2285}
2286
2287#endif // QT_NO_DATASTREAM
2288
2289
2290/*****************************************************************************
2291 QFontInfo member functions
2292 *****************************************************************************/
2293
2294/*!
2295 \class QFontInfo
2296 \reentrant
2297
2298 \brief The QFontInfo class provides general information about fonts.
2299
2300 \ingroup appearance
2301 \ingroup shared
2302
2303 The QFontInfo class provides the same access functions as QFont,
2304 e.g. family(), pointSize(), italic(), weight(), fixedPitch(),
2305 styleHint() etc. But whilst the QFont access functions return the
2306 values that were set, a QFontInfo object returns the values that
2307 apply to the font that will actually be used to draw the text.
2308
2309 For example, when the program asks for a 25pt Courier font on a
2310 machine that has a non-scalable 24pt Courier font, QFont will
2311 (normally) use the 24pt Courier for rendering. In this case,
2312 QFont::pointSize() returns 25 and QFontInfo::pointSize() returns
2313 24.
2314
2315 There are three ways to create a QFontInfo object.
2316 \list 1
2317 \o Calling the QFontInfo constructor with a QFont creates a font
2318 info object for a screen-compatible font, i.e. the font cannot be
2319 a printer font. If the font is changed later, the font
2320 info object is \e not updated.
2321
2322 (Note: If you use a printer font the values returned may be
2323 inaccurate. Printer fonts are not always accessible so the nearest
2324 screen font is used if a printer font is supplied.)
2325
2326 \o QWidget::fontInfo() returns the font info for a widget's font.
2327 This is equivalent to calling QFontInfo(widget->font()). If the
2328 widget's font is changed later, the font info object is \e not
2329 updated.
2330
2331 \o QPainter::fontInfo() returns the font info for a painter's
2332 current font. If the painter's font is changed later, the font
2333 info object is \e not updated.
2334 \endlist
2335
2336 \sa QFont QFontMetrics QFontDatabase
2337*/
2338
2339/*!
2340 Constructs a font info object for \a font.
2341
2342 The font must be screen-compatible, i.e. a font you use when
2343 drawing text in \link QWidget widgets\endlink or \link QPixmap
2344 pixmaps\endlink, not QPicture or QPrinter.
2345
2346 The font info object holds the information for the font that is
2347 passed in the constructor at the time it is created, and is not
2348 updated if the font's attributes are changed later.
2349
2350 Use QPainter::fontInfo() to get the font info when painting.
2351 This will give correct results also when painting on paint device
2352 that is not screen-compatible.
2353*/
2354QFontInfo::QFontInfo(const QFont &font)
2355 : d(font.d.data())
2356{
2357}
2358
2359/*!
2360 Constructs a copy of \a fi.
2361*/
2362QFontInfo::QFontInfo(const QFontInfo &fi)
2363 : d(fi.d.data())
2364{
2365}
2366
2367/*!
2368 Destroys the font info object.
2369*/
2370QFontInfo::~QFontInfo()
2371{
2372}
2373
2374/*!
2375 Assigns the font info in \a fi.
2376*/
2377QFontInfo &QFontInfo::operator=(const QFontInfo &fi)
2378{
2379 d = fi.d.data();
2380 return *this;
2381}
2382
2383/*!
2384 Returns the family name of the matched window system font.
2385
2386 \sa QFont::family()
2387*/
2388QString QFontInfo::family() const
2389{
2390 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2391 Q_ASSERT(engine != 0);
2392 return engine->fontDef.family;
2393}
2394
2395/*!
2396 Returns the point size of the matched window system font.
2397
2398 \sa pointSizeF() QFont::pointSize()
2399*/
2400int QFontInfo::pointSize() const
2401{
2402 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2403 Q_ASSERT(engine != 0);
2404 return qRound(engine->fontDef.pointSize);
2405}
2406
2407/*!
2408 Returns the point size of the matched window system font.
2409
2410 \sa QFont::pointSizeF()
2411*/
2412qreal QFontInfo::pointSizeF() const
2413{
2414 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2415 Q_ASSERT(engine != 0);
2416 return engine->fontDef.pointSize;
2417}
2418
2419/*!
2420 Returns the pixel size of the matched window system font.
2421
2422 \sa QFont::pointSize()
2423*/
2424int QFontInfo::pixelSize() const
2425{
2426 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2427 Q_ASSERT(engine != 0);
2428 return engine->fontDef.pixelSize;
2429}
2430
2431/*!
2432 Returns the italic value of the matched window system font.
2433
2434 \sa QFont::italic()
2435*/
2436bool QFontInfo::italic() const
2437{
2438 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2439 Q_ASSERT(engine != 0);
2440 return engine->fontDef.style != QFont::StyleNormal;
2441}
2442
2443/*!
2444 Returns the style value of the matched window system font.
2445
2446 \sa QFont::style()
2447*/
2448QFont::Style QFontInfo::style() const
2449{
2450 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2451 Q_ASSERT(engine != 0);
2452 return (QFont::Style)engine->fontDef.style;
2453}
2454
2455/*!
2456 Returns the weight of the matched window system font.
2457
2458 \sa QFont::weight(), bold()
2459*/
2460int QFontInfo::weight() const
2461{
2462 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2463 Q_ASSERT(engine != 0);
2464 return engine->fontDef.weight;
2465
2466}
2467
2468/*!
2469 \fn bool QFontInfo::bold() const
2470
2471 Returns true if weight() would return a value greater than
2472 QFont::Normal; otherwise returns false.
2473
2474 \sa weight(), QFont::bold()
2475*/
2476
2477/*!
2478 Returns the underline value of the matched window system font.
2479
2480 \sa QFont::underline()
2481
2482 \internal
2483
2484 Here we read the underline flag directly from the QFont.
2485 This is OK for X11 and for Windows because we always get what we want.
2486*/
2487bool QFontInfo::underline() const
2488{
2489 return d->underline;
2490}
2491
2492/*!
2493 Returns the overline value of the matched window system font.
2494
2495 \sa QFont::overline()
2496
2497 \internal
2498
2499 Here we read the overline flag directly from the QFont.
2500 This is OK for X11 and for Windows because we always get what we want.
2501*/
2502bool QFontInfo::overline() const
2503{
2504 return d->overline;
2505}
2506
2507/*!
2508 Returns the strikeout value of the matched window system font.
2509
2510 \sa QFont::strikeOut()
2511
2512 \internal Here we read the strikeOut flag directly from the QFont.
2513 This is OK for X11 and for Windows because we always get what we want.
2514*/
2515bool QFontInfo::strikeOut() const
2516{
2517 return d->strikeOut;
2518}
2519
2520/*!
2521 Returns the fixed pitch value of the matched window system font.
2522
2523 \sa QFont::fixedPitch()
2524*/
2525bool QFontInfo::fixedPitch() const
2526{
2527 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2528 Q_ASSERT(engine != 0);
2529#ifdef Q_OS_MAC
2530 if (!engine->fontDef.fixedPitchComputed) {
2531 QChar ch[2] = { QLatin1Char('i'), QLatin1Char('m') };
2532 QGlyphLayoutArray<2> g;
2533 int l = 2;
2534 engine->stringToCMap(ch, 2, &g, &l, 0);
2535 engine->fontDef.fixedPitch = g.advances_x[0] == g.advances_x[1];
2536 engine->fontDef.fixedPitchComputed = true;
2537 }
2538#endif
2539 return engine->fontDef.fixedPitch;
2540}
2541
2542/*!
2543 Returns the style of the matched window system font.
2544
2545 Currently only returns the style hint set in QFont.
2546
2547 \sa QFont::styleHint() QFont::StyleHint
2548*/
2549QFont::StyleHint QFontInfo::styleHint() const
2550{
2551 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2552 Q_ASSERT(engine != 0);
2553 return (QFont::StyleHint) engine->fontDef.styleHint;
2554}
2555
2556/*!
2557 Returns true if the font is a raw mode font; otherwise returns
2558 false.
2559
2560 If it is a raw mode font, all other functions in QFontInfo will
2561 return the same values set in the QFont, regardless of the font
2562 actually used.
2563
2564 \sa QFont::rawMode()
2565*/
2566bool QFontInfo::rawMode() const
2567{
2568 return d->rawMode;
2569}
2570
2571/*!
2572 Returns true if the matched window system font is exactly the same
2573 as the one specified by the font; otherwise returns false.
2574
2575 \sa QFont::exactMatch()
2576*/
2577bool QFontInfo::exactMatch() const
2578{
2579 QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
2580 Q_ASSERT(engine != 0);
2581 return (d->rawMode
2582 ? engine->type() != QFontEngine::Box
2583 : d->request.exactMatch(engine->fontDef));
2584}
2585
2586
2587
2588
2589// **********************************************************************
2590// QFontCache
2591// **********************************************************************
2592
2593#ifdef QFONTCACHE_DEBUG
2594// fast timeouts for debugging
2595static const int fast_timeout = 1000; // 1s
2596static const int slow_timeout = 5000; // 5s
2597#else
2598static const int fast_timeout = 10000; // 10s
2599static const int slow_timeout = 300000; // 5m
2600#endif // QFONTCACHE_DEBUG
2601
2602const uint QFontCache::min_cost = 4*1024; // 4mb
2603
2604#ifdef QT_NO_THREAD
2605Q_GLOBAL_STATIC(QFontCache, theFontCache)
2606
2607QFontCache *QFontCache::instance()
2608{
2609 return theFontCache();
2610}
2611
2612void QFontCache::cleanup()
2613{
2614}
2615#else
2616Q_GLOBAL_STATIC(QThreadStorage<QFontCache *>, theFontCache)
2617
2618QFontCache *QFontCache::instance()
2619{
2620 QFontCache *&fontCache = theFontCache()->localData();
2621 if (!fontCache)
2622 fontCache = new QFontCache;
2623 return fontCache;
2624}
2625
2626void QFontCache::cleanup()
2627{
2628 QThreadStorage<QFontCache *> *cache = 0;
2629 QT_TRY {
2630 cache = theFontCache();
2631 } QT_CATCH (const std::bad_alloc &) {
2632 // no cache - just ignore
2633 }
2634 if (cache && cache->hasLocalData())
2635 cache->setLocalData(0);
2636}
2637#endif // QT_NO_THREAD
2638
2639QFontCache::QFontCache()
2640 : QObject(), total_cost(0), max_cost(min_cost),
2641 current_timestamp(0), fast(false), timer_id(-1)
2642{
2643}
2644
2645QFontCache::~QFontCache()
2646{
2647 clear();
2648 {
2649 EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
2650 end = engineDataCache.constEnd();
2651 while (it != end) {
2652 if (it.value()->ref == 0)
2653 delete it.value();
2654 else
2655 FC_DEBUG("QFontCache::~QFontCache: engineData %p still has refcount %d",
2656 it.value(), int(it.value()->ref));
2657 ++it;
2658 }
2659 }
2660 EngineCache::ConstIterator it = engineCache.constBegin(),
2661 end = engineCache.constEnd();
2662 while (it != end) {
2663 if (--it.value().data->cache_count == 0) {
2664 if (it.value().data->ref == 0) {
2665 FC_DEBUG("QFontCache::~QFontCache: deleting engine %p key=(%d / %g %g %d %d %d)",
2666 it.value().data, it.key().script, it.key().def.pointSize,
2667 it.key().def.pixelSize, it.key().def.weight, it.key().def.style,
2668 it.key().def.fixedPitch);
2669
2670 delete it.value().data;
2671 } else {
2672 FC_DEBUG("QFontCache::~QFontCache: engine = %p still has refcount %d",
2673 it.value().data, int(it.value().data->ref));
2674 }
2675 }
2676 ++it;
2677 }
2678}
2679
2680void QFontCache::clear()
2681{
2682 {
2683 EngineDataCache::Iterator it = engineDataCache.begin(),
2684 end = engineDataCache.end();
2685 while (it != end) {
2686 QFontEngineData *data = it.value();
2687#if !defined(Q_WS_MAC)
2688 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
2689 if (data->engines[i]) {
2690 data->engines[i]->ref.deref();
2691 data->engines[i] = 0;
2692 }
2693 }
2694#else
2695 if (data->engine) {
2696 data->engine->ref.deref();
2697 data->engine = 0;
2698 }
2699#endif
2700 ++it;
2701 }
2702 }
2703
2704 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
2705 it != end; ++it) {
2706 if (it->data->ref == 0) {
2707 delete it->data;
2708 it->data = 0;
2709 }
2710 }
2711
2712 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
2713 it != end; ++it) {
2714 if (it->data && it->data->ref == 0) {
2715 delete it->data;
2716 it->data = 0;
2717 }
2718 }
2719
2720 engineCache.clear();
2721}
2722
2723#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
2724void QFontCache::removeEngineForFont(const QByteArray &_fontName)
2725{
2726
2727 /* This could be optimized but the code becomes much more complex if we want to handle multi
2728 * font engines and it is probably not worth it. Therefore we just clear the entire font cache.
2729 */
2730 Q_UNUSED(_fontName);
2731 clear();
2732}
2733#endif
2734
2735QFontEngineData *QFontCache::findEngineData(const Key &key) const
2736{
2737 EngineDataCache::ConstIterator it = engineDataCache.find(key),
2738 end = engineDataCache.end();
2739 if (it == end) return 0;
2740
2741 // found
2742 return it.value();
2743}
2744
2745void QFontCache::insertEngineData(const Key &key, QFontEngineData *engineData)
2746{
2747 FC_DEBUG("QFontCache: inserting new engine data %p", engineData);
2748
2749 engineDataCache.insert(key, engineData);
2750 increaseCost(sizeof(QFontEngineData));
2751}
2752
2753QFontEngine *QFontCache::findEngine(const Key &key)
2754{
2755 EngineCache::Iterator it = engineCache.find(key),
2756 end = engineCache.end();
2757 if (it == end) return 0;
2758
2759 // found... update the hitcount and timestamp
2760 it.value().hits++;
2761 it.value().timestamp = ++current_timestamp;
2762
2763 FC_DEBUG("QFontCache: found font engine\n"
2764 " %p: timestamp %4u hits %3u ref %2d/%2d, type '%s'",
2765 it.value().data, it.value().timestamp, it.value().hits,
2766 int(it.value().data->ref), it.value().data->cache_count,
2767 it.value().data->name());
2768
2769 return it.value().data;
2770}
2771
2772void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
2773{
2774 FC_DEBUG("QFontCache: inserting new engine %p", engine);
2775
2776 Engine data(engine);
2777 data.timestamp = ++current_timestamp;
2778
2779 engineCache.insert(key, data);
2780
2781 // only increase the cost if this is the first time we insert the engine
2782 if (engine->cache_count == 0)
2783 increaseCost(engine->cache_cost);
2784
2785 ++engine->cache_count;
2786}
2787
2788void QFontCache::increaseCost(uint cost)
2789{
2790 cost = (cost + 512) / 1024; // store cost in kb
2791 cost = cost > 0 ? cost : 1;
2792 total_cost += cost;
2793
2794 FC_DEBUG(" COST: increased %u kb, total_cost %u kb, max_cost %u kb",
2795 cost, total_cost, max_cost);
2796
2797 if (total_cost > max_cost) {
2798 max_cost = total_cost;
2799
2800 if (timer_id == -1 || ! fast) {
2801 FC_DEBUG(" TIMER: starting fast timer (%d ms)", fast_timeout);
2802
2803 if (timer_id != -1) killTimer(timer_id);
2804 timer_id = startTimer(fast_timeout);
2805 fast = true;
2806 }
2807 }
2808}
2809
2810void QFontCache::decreaseCost(uint cost)
2811{
2812 cost = (cost + 512) / 1024; // cost is stored in kb
2813 cost = cost > 0 ? cost : 1;
2814 Q_ASSERT(cost <= total_cost);
2815 total_cost -= cost;
2816
2817 FC_DEBUG(" COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
2818 cost, total_cost, max_cost);
2819}
2820
2821#if defined(Q_WS_WIN) || defined (Q_WS_QWS)
2822void QFontCache::cleanupPrinterFonts()
2823{
2824 FC_DEBUG("QFontCache::cleanupPrinterFonts");
2825
2826 {
2827 FC_DEBUG(" CLEAN engine data:");
2828
2829 // clean out all unused engine data
2830 EngineDataCache::Iterator it = engineDataCache.begin(),
2831 end = engineDataCache.end();
2832 while (it != end) {
2833 if (it.key().screen == 0) {
2834 ++it;
2835 continue;
2836 }
2837
2838 if(it.value()->ref != 0) {
2839 for(int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
2840 if(it.value()->engines[i]) {
2841 it.value()->engines[i]->ref.deref();
2842 it.value()->engines[i] = 0;
2843 }
2844 }
2845 ++it;
2846 } else {
2847
2848 EngineDataCache::Iterator rem = it++;
2849
2850 decreaseCost(sizeof(QFontEngineData));
2851
2852 FC_DEBUG(" %p", rem.value());
2853
2854 delete rem.value();
2855 engineDataCache.erase(rem);
2856 }
2857 }
2858 }
2859
2860 EngineCache::Iterator it = engineCache.begin(),
2861 end = engineCache.end();
2862 while(it != end) {
2863 if (it.value().data->ref != 0 || it.key().screen == 0) {
2864 ++it;
2865 continue;
2866 }
2867
2868 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
2869 it.value().data, it.value().timestamp, it.value().hits,
2870 int(it.value().data->ref), it.value().data->cache_count,
2871 it.value().data->name());
2872
2873 if (--it.value().data->cache_count == 0) {
2874 FC_DEBUG(" DELETE: last occurrence in cache");
2875
2876 decreaseCost(it.value().data->cache_cost);
2877 delete it.value().data;
2878 }
2879
2880 engineCache.erase(it++);
2881 }
2882}
2883#endif
2884
2885void QFontCache::timerEvent(QTimerEvent *)
2886{
2887 FC_DEBUG("QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
2888 current_timestamp);
2889
2890 if (total_cost <= max_cost && max_cost <= min_cost) {
2891 FC_DEBUG(" cache redused sufficiently, stopping timer");
2892
2893 killTimer(timer_id);
2894 timer_id = -1;
2895 fast = false;
2896
2897 return;
2898 }
2899
2900 // go through the cache and count up everything in use
2901 uint in_use_cost = 0;
2902
2903 {
2904 FC_DEBUG(" SWEEP engine data:");
2905
2906 // make sure the cost of each engine data is at least 1kb
2907 const uint engine_data_cost =
2908 sizeof(QFontEngineData) > 1024 ? sizeof(QFontEngineData) : 1024;
2909
2910 EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
2911 end = engineDataCache.constEnd();
2912 for (; it != end; ++it) {
2913#ifdef QFONTCACHE_DEBUG
2914 FC_DEBUG(" %p: ref %2d", it.value(), int(it.value()->ref));
2915
2916# if defined(Q_WS_X11) || defined(Q_WS_WIN)
2917 // print out all engines
2918 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
2919 if (! it.value()->engines[i])
2920 continue;
2921 FC_DEBUG(" contains %p", it.value()->engines[i]);
2922 }
2923# endif // Q_WS_X11 || Q_WS_WIN
2924#endif // QFONTCACHE_DEBUG
2925
2926 if (it.value()->ref != 0)
2927 in_use_cost += engine_data_cost;
2928 }
2929 }
2930
2931 {
2932 FC_DEBUG(" SWEEP engine:");
2933
2934 EngineCache::ConstIterator it = engineCache.constBegin(),
2935 end = engineCache.constEnd();
2936 for (; it != end; ++it) {
2937 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
2938 it.value().data, it.value().timestamp, it.value().hits,
2939 int(it.value().data->ref), it.value().data->cache_count,
2940 it.value().data->cache_cost);
2941
2942 if (it.value().data->ref != 0)
2943 in_use_cost += it.value().data->cache_cost / it.value().data->cache_count;
2944 }
2945
2946 // attempt to make up for rounding errors
2947 in_use_cost += engineCache.size();
2948 }
2949
2950 in_use_cost = (in_use_cost + 512) / 1024; // cost is stored in kb
2951
2952 /*
2953 calculate the new maximum cost for the cache
2954
2955 NOTE: in_use_cost is *not* correct due to rounding errors in the
2956 above algorithm. instead of worrying about getting the
2957 calculation correct, we are more interested in speed, and use
2958 in_use_cost as a floor for new_max_cost
2959 */
2960 uint new_max_cost = qMax(qMax(max_cost / 2, in_use_cost), min_cost);
2961
2962 FC_DEBUG(" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
2963 in_use_cost, total_cost, max_cost, new_max_cost);
2964
2965 if (new_max_cost == max_cost) {
2966 if (fast) {
2967 FC_DEBUG(" cannot shrink cache, slowing timer");
2968
2969 killTimer(timer_id);
2970 timer_id = startTimer(slow_timeout);
2971 fast = false;
2972 }
2973
2974 return;
2975 } else if (! fast) {
2976 FC_DEBUG(" dropping into passing gear");
2977
2978 killTimer(timer_id);
2979 timer_id = startTimer(fast_timeout);
2980 fast = true;
2981 }
2982
2983 max_cost = new_max_cost;
2984
2985 {
2986 FC_DEBUG(" CLEAN engine data:");
2987
2988 // clean out all unused engine data
2989 EngineDataCache::Iterator it = engineDataCache.begin(),
2990 end = engineDataCache.end();
2991 while (it != end) {
2992 if (it.value()->ref != 0) {
2993 ++it;
2994 continue;
2995 }
2996
2997 EngineDataCache::Iterator rem = it++;
2998
2999 decreaseCost(sizeof(QFontEngineData));
3000
3001 FC_DEBUG(" %p", rem.value());
3002
3003 delete rem.value();
3004 engineDataCache.erase(rem);
3005 }
3006 }
3007
3008 // clean out the engine cache just enough to get below our new max cost
3009 uint current_cost;
3010 do {
3011 current_cost = total_cost;
3012
3013 EngineCache::Iterator it = engineCache.begin(),
3014 end = engineCache.end();
3015 // determine the oldest and least popular of the unused engines
3016 uint oldest = ~0u;
3017 uint least_popular = ~0u;
3018
3019 for (; it != end; ++it) {
3020 if (it.value().data->ref != 0)
3021 continue;
3022
3023 if (it.value().timestamp < oldest &&
3024 it.value().hits <= least_popular) {
3025 oldest = it.value().timestamp;
3026 least_popular = it.value().hits;
3027 }
3028 }
3029
3030 FC_DEBUG(" oldest %u least popular %u", oldest, least_popular);
3031
3032 for (it = engineCache.begin(); it != end; ++it) {
3033 if (it.value().data->ref == 0 &&
3034 it.value().timestamp == oldest &&
3035 it.value().hits == least_popular)
3036 break;
3037 }
3038
3039 if (it != end) {
3040 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
3041 it.value().data, it.value().timestamp, it.value().hits,
3042 int(it.value().data->ref), it.value().data->cache_count,
3043 it.value().data->name());
3044
3045 if (--it.value().data->cache_count == 0) {
3046 FC_DEBUG(" DELETE: last occurrence in cache");
3047
3048 decreaseCost(it.value().data->cache_cost);
3049 delete it.value().data;
3050 } else {
3051 /*
3052 this particular font engine is in the cache multiple
3053 times... set current_cost to zero, so that we can
3054 keep looping to get rid of all occurrences
3055 */
3056 current_cost = 0;
3057 }
3058
3059 engineCache.erase(it);
3060 }
3061 } while (current_cost != total_cost && total_cost > max_cost);
3062}
3063
3064
3065#ifndef QT_NO_DEBUG_STREAM
3066QDebug operator<<(QDebug stream, const QFont &font)
3067{
3068 return stream << "QFont(" << font.toString() << ')';
3069}
3070#endif
3071
3072QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.