You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qt3/src/kernel/qfontdatabase_x11.cpp

2032 lines
61 KiB

/****************************************************************************
**
** Implementation of platform specific QFontDatabase
**
** Created : 970521
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free Qt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** This file may be used under the terms of the Q Public License as
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
** included in the packaging of this file. Licensees holding valid Qt
** Commercial licenses may use this file in accordance with the Qt
** Commercial License Agreement provided with the Software.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/
#include <qplatformdefs.h>
#include <qdatetime.h>
#include <qpaintdevicemetrics.h>
#include "qt_x11_p.h"
#include <ctype.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#ifndef QT_NO_XFTFREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#endif
#ifndef QT_XFT2
#define FcBool Bool
#define FcTrue True
#define FcFalse False
#endif
#ifdef QFONTDATABASE_DEBUG
# define FD_DEBUG qDebug
#else
# define FD_DEBUG if (FALSE) qDebug
#endif // QFONTDATABASE_DEBUG
// from qfont_x11.cpp
extern double qt_pointSize(double pixelSize, QPaintDevice *paintdevice, int screen);
extern double qt_pixelSize(double pointSize, QPaintDevice *paintdevice, int screen);
static inline void capitalize ( char *s )
{
bool space = TRUE;
while( *s ) {
if ( space )
*s = toupper( *s );
space = ( *s == ' ' );
++s;
}
}
// ----- begin of generated code -----
#define make_tag( c1, c2, c3, c4 ) \
( (((unsigned int)c1)<<24) | (((unsigned int)c2)<<16) | \
(((unsigned int)c3)<<8) | ((unsigned int)c4) )
struct XlfdEncoding {
const char *name;
int id;
int mib;
unsigned int hash1;
unsigned int hash2;
};
static const XlfdEncoding xlfd_encoding[] = {
{ "iso8859-1", 0, 4, make_tag('i','s','o','8'), make_tag('5','9','-','1') },
{ "iso8859-2", 1, 5, make_tag('i','s','o','8'), make_tag('5','9','-','2') },
{ "iso8859-3", 2, 6, make_tag('i','s','o','8'), make_tag('5','9','-','3') },
{ "iso8859-4", 3, 7, make_tag('i','s','o','8'), make_tag('5','9','-','4') },
{ "iso8859-9", 4, 12, make_tag('i','s','o','8'), make_tag('5','9','-','9') },
{ "iso8859-10", 5, 13, make_tag('i','s','o','8'), make_tag('9','-','1','0') },
{ "iso8859-13", 6, 109, make_tag('i','s','o','8'), make_tag('9','-','1','3') },
{ "iso8859-14", 7, 110, make_tag('i','s','o','8'), make_tag('9','-','1','4') },
{ "iso8859-15", 8, 111, make_tag('i','s','o','8'), make_tag('9','-','1','5') },
{ "hp-roman8", 9, 2004, make_tag('h','p','-','r'), make_tag('m','a','n','8') },
{ "jisx0208*-0", 10, 63, make_tag('j','i','s','x'), 0 },
#define LAST_LATIN_ENCODING 10
{ "iso8859-5", 11, 8, make_tag('i','s','o','8'), make_tag('5','9','-','5') },
{ "*-cp1251", 12, 2251, 0, make_tag('1','2','5','1') },
{ "koi8-ru", 13, 2084, make_tag('k','o','i','8'), make_tag('8','-','r','u') },
{ "koi8-u", 14, 2088, make_tag('k','o','i','8'), make_tag('i','8','-','u') },
{ "koi8-r", 15, 2084, make_tag('k','o','i','8'), make_tag('i','8','-','r') },
{ "iso8859-7", 16, 10, make_tag('i','s','o','8'), make_tag('5','9','-','7') },
{ "iso10646-1", 17, 0, make_tag('i','s','o','1'), make_tag('4','6','-','1') },
{ "iso8859-8", 18, 85, make_tag('i','s','o','8'), make_tag('5','9','-','8') },
{ "gb18030-0", 19, -114, make_tag('g','b','1','8'), make_tag('3','0','-','0') },
{ "gb18030.2000-0", 20, -113, make_tag('g','b','1','8'), make_tag('0','0','-','0') },
{ "gbk-0", 21, -113, make_tag('g','b','k','-'), make_tag('b','k','-','0') },
{ "gb2312.*-0", 22, 57, make_tag('g','b','2','3'), 0 },
{ "jisx0201*-0", 23, 15, make_tag('j','i','s','x'), 0 },
{ "ksc5601*-*", 24, 36, make_tag('k','s','c','5'), 0 },
{ "big5hkscs-0", 25, -2101, make_tag('b','i','g','5'), make_tag('c','s','-','0') },
{ "hkscs-1", 26, -2101, make_tag('h','k','s','c'), make_tag('c','s','-','1') },
{ "big5*-*", 27, -2026, make_tag('b','i','g','5'), 0 },
{ "tscii-*", 28, 2028, make_tag('t','s','c','i'), 0 },
{ "tis620*-*", 29, 2259, make_tag('t','i','s','6'), 0 },
{ "iso8859-11", 30, 2259, make_tag('i','s','o','8'), make_tag('9','-','1','1') },
{ "mulelao-1", 31, -4242, make_tag('m','u','l','e'), make_tag('a','o','-','1') },
{ "ethiopic-unicode", 32, 0, make_tag('e','t','h','i'), make_tag('c','o','d','e') },
{ "unicode-*", 33, 0, make_tag('u','n','i','c'), 0 },
{ "*-symbol", 34, 0, 0, make_tag('m','b','o','l') },
{ "*-fontspecific", 35, 0, 0, make_tag('i','f','i','c') },
{ "fontspecific-*", 36, 0, make_tag('f','o','n','t'), 0 },
{ 0, 0, 0, 0, 0 }
};
static const char scripts_for_xlfd_encoding[37][61] = {
// iso8859-1
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-2
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-3
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-4
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-9
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-10
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-13
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-14
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-15
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// hp-roman8
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// jisx0208*-0
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0 },
// iso8859-5
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// *-cp1251
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// koi8-ru
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// koi8-u
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// koi8-r
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-7
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso10646-1
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-8
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// gb18030-0
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0 },
// gb18030.2000-0
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0 },
// gbk-0
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0 },
// gb2312.*-0
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0 },
// jisx0201*-0
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0 },
// ksc5601*-*
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1 },
// big5hkscs-0
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0 },
// hkscs-1
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0 },
// big5*-*
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0 },
// tscii-*
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// tis620*-*
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// iso8859-11
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// mulelao-1
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// ethiopic-unicode
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// unicode-*
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 },
// *-symbol
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0 },
// *-fontspecific
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0 },
// fontspecific-*
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0 }
};
// ----- end of generated code -----
const int numEncodings = sizeof( xlfd_encoding ) / sizeof( XlfdEncoding ) - 1;
int qt_xlfd_encoding_id( const char *encoding )
{
// qDebug("looking for encoding id for '%s'", encoding );
int len = strlen( encoding );
if ( len < 4 )
return -1;
unsigned int hash1 = make_tag( encoding[0], encoding[1], encoding[2], encoding[3] );
const char *ch = encoding + len - 4;
unsigned int hash2 = make_tag( ch[0], ch[1], ch[2], ch[3] );
const XlfdEncoding *enc = xlfd_encoding;
for ( ; enc->name; ++enc ) {
if ( (enc->hash1 && enc->hash1 != hash1) ||
(enc->hash2 && enc->hash2 != hash2) )
continue;
// hashes match, do a compare if strings match
// the enc->name can contain '*'s we have to interpret correctly
const char *n = enc->name;
const char *e = encoding;
while ( 1 ) {
// qDebug("bol: *e='%c', *n='%c'", *e, *n );
if ( *e == '\0' ) {
if ( *n )
break;
// qDebug( "found encoding id %d", enc->id );
return enc->id;
}
if ( *e == *n ) {
++e;
++n;
continue;
}
if ( *n != '*' )
break;
++n;
// qDebug("skip: *e='%c', *n='%c'", *e, *n );
while ( *e && *e != *n )
++e;
}
}
// qDebug( "couldn't find encoding %s", encoding );
return -1;
}
int qt_mib_for_xlfd_encoding( const char *encoding )
{
int id = qt_xlfd_encoding_id( encoding );
if ( id != -1 ) return xlfd_encoding[id].mib;
return 0;
}
int qt_encoding_id_for_mib( int mib )
{
const XlfdEncoding *enc = xlfd_encoding;
for ( ; enc->name; ++enc ) {
if ( enc->mib == mib )
return enc->id;
}
return -1;
}
static const char * xlfd_for_id( int id )
{
// special case: -1 returns the "*-*" encoding, allowing us to do full
// database population in a single X server round trip.
if ( id < 0 || id > numEncodings )
return "*-*";
return xlfd_encoding[id].name;
}
enum XLFDFieldNames {
Foundry,
Family,
Weight,
Slant,
Width,
AddStyle,
PixelSize,
PointSize,
ResolutionX,
ResolutionY,
Spacing,
AverageWidth,
CharsetRegistry,
CharsetEncoding,
NFontFields
};
// Splits an X font name into fields separated by '-'
static bool parseXFontName( char *fontName, char **tokens )
{
if ( ! fontName || fontName[0] == '0' || fontName[0] != '-' ) {
tokens[0] = 0;
return FALSE;
}
int i;
++fontName;
for ( i = 0; i < NFontFields && fontName && fontName[0]; ++i ) {
tokens[i] = fontName;
for ( ;; ++fontName ) {
if ( *fontName == '-' )
break;
if ( ! *fontName ) {
fontName = 0;
break;
}
}
if ( fontName ) *fontName++ = '\0';
}
if ( i < NFontFields ) {
for ( int j = i ; j < NFontFields; ++j )
tokens[j] = 0;
return FALSE;
}
return TRUE;
}
static inline bool isZero(char *x)
{
return (x[0] == '0' && x[1] == 0);
}
static inline bool isScalable( char **tokens )
{
return (isZero(tokens[PixelSize]) &&
isZero(tokens[PointSize]) &&
isZero(tokens[AverageWidth]));
}
static inline bool isSmoothlyScalable( char **tokens )
{
return (isZero(tokens[ResolutionX]) &&
isZero(tokens[ResolutionY]));
}
static inline bool isFixedPitch( char **tokens )
{
return (tokens[Spacing][0] == 'm' ||
tokens[Spacing][0] == 'c' ||
tokens[Spacing][0] == 'M' ||
tokens[Spacing][0] == 'C');
}
/*
Fills in a font definition (QFontDef) from an XLFD (X Logical Font
Description).
Returns TRUE if the the given xlfd is valid. The fields lbearing
and rbearing are not given any values.
*/
bool qt_fillFontDef( const QCString &xlfd, QFontDef *fd, int screen )
{
char *tokens[NFontFields];
QCString buffer = xlfd.copy();
if ( ! parseXFontName(buffer.data(), tokens) )
return FALSE;
capitalize(tokens[Family]);
capitalize(tokens[Foundry]);
fd->family = QString::fromLatin1(tokens[Family]);
QString foundry = QString::fromLatin1(tokens[Foundry]);
if ( ! foundry.isEmpty() && foundry != QString::fromLatin1("*") )
fd->family +=
QString::fromLatin1(" [") + foundry + QString::fromLatin1("]");
if ( qstrlen( tokens[AddStyle] ) > 0 )
fd->addStyle = QString::fromLatin1(tokens[AddStyle]);
else
fd->addStyle = QString::null;
fd->pointSize = atoi(tokens[PointSize]);
fd->styleHint = QFont::AnyStyle; // ### any until we match families
char slant = tolower( (uchar) tokens[Slant][0] );
fd->italic = ( slant == 'o' || slant == 'i' );
char fixed = tolower( (uchar) tokens[Spacing][0] );
fd->fixedPitch = ( fixed == 'm' || fixed == 'c' );
fd->weight = getFontWeight( tokens[Weight] );
int r = atoi(tokens[ResolutionY]);
fd->pixelSize = atoi(tokens[PixelSize]);
// not "0" or "*", or required DPI
if ( r && fd->pixelSize && QPaintDevice::x11AppDpiY( screen ) &&
r != QPaintDevice::x11AppDpiY( screen ) ) {
// calculate actual pointsize for display DPI
fd->pointSize = qRound(qt_pointSize(fd->pixelSize, 0, screen) * 10.);
} else if ( fd->pixelSize == 0 && fd->pointSize ) {
// calculate pixel size from pointsize/dpi
fd->pixelSize = qRound(qt_pixelSize(fd->pointSize / 10., 0, screen));
}
return TRUE;
}
/*
Fills in a font definition (QFontDef) from the font properties in an
XFontStruct.
Returns TRUE if the QFontDef could be filled with properties from
the XFontStruct. The fields lbearing and rbearing are not given any
values.
*/
static bool qt_fillFontDef( XFontStruct *fs, QFontDef *fd, int screen )
{
unsigned long value;
if ( fs && !XGetFontProperty( fs, XA_FONT, &value ) )
return FALSE;
char *n = XGetAtomName( QPaintDevice::x11AppDisplay(), value );
QCString xlfd( n );
if ( n )
XFree( n );
return qt_fillFontDef( xlfd.lower(), fd, screen );
}
static QtFontStyle::Key getStyle( char ** tokens )
{
QtFontStyle::Key key;
char slant0 = tolower( (uchar) tokens[Slant][0] );
if ( slant0 == 'r' ) {
if ( tokens[Slant][1]) {
char slant1 = tolower( (uchar) tokens[Slant][1] );
if ( slant1 == 'o' )
key.oblique = TRUE;
else if ( slant1 == 'i' )
key.italic = TRUE;
}
} else if ( slant0 == 'o' )
key.oblique = TRUE;
else if ( slant0 == 'i' )
key.italic = TRUE;
key.weight = getFontWeight( tokens[Weight] );
if ( qstrcmp( tokens[Width], "normal" ) == 0 ) {
key.stretch = 100;
} else if ( qstrcmp( tokens[Width], "semi condensed" ) == 0 ||
qstrcmp( tokens[Width], "semicondensed" ) == 0 ) {
key.stretch = 90;
} else if ( qstrcmp( tokens[Width], "condensed" ) == 0 ) {
key.stretch = 80;
} else if ( qstrcmp( tokens[Width], "narrow" ) == 0 ) {
key.stretch = 60;
}
return key;
}
extern bool qt_has_xft; // defined in qfont_x11.cpp
static bool xlfdsFullyLoaded = FALSE;
static unsigned char encodingLoaded[numEncodings];
static void loadXlfds( const char *reqFamily, int encoding_id )
{
QtFontFamily *fontFamily = reqFamily ? db->family( reqFamily ) : 0;
// make sure we don't load twice
if ( (encoding_id == -1 && xlfdsFullyLoaded) || (encoding_id != -1 && encodingLoaded[encoding_id]) )
return;
if ( fontFamily && fontFamily->xlfdLoaded )
return;
#ifdef QT_XFT2
if ( !qt_has_xft ) {
#endif // QT_XFT2
int fontCount;
// force the X server to give us XLFDs
QCString xlfd_pattern = "-*-";
xlfd_pattern += reqFamily ? reqFamily : "*";
xlfd_pattern += "-*-*-*-*-*-*-*-*-*-*-";
xlfd_pattern += xlfd_for_id( encoding_id );
char **fontList = XListFonts( QPaintDevice::x11AppDisplay(),
xlfd_pattern.data(),
0xffff, &fontCount );
// qDebug("requesting xlfd='%s', got %d fonts", xlfd_pattern.data(), fontCount );
char *tokens[NFontFields];
for( int i = 0 ; i < fontCount ; i++ ) {
if ( ! parseXFontName( fontList[i], tokens ) ) continue;
// get the encoding_id for this xlfd. we need to do this
// here, since we can pass -1 to this function to do full
// database population
*(tokens[CharsetEncoding]-1) = '-';
int encoding_id = qt_xlfd_encoding_id( tokens[CharsetRegistry] );
if ( encoding_id == -1 )
continue;
char *familyName = tokens[Family];
capitalize( familyName );
char *foundryName = tokens[Foundry];
capitalize( foundryName );
QtFontStyle::Key styleKey = getStyle( tokens );
bool smooth_scalable = FALSE;
bool bitmap_scalable = FALSE;
if ( isScalable(tokens) ) {
if ( isSmoothlyScalable( tokens ) )
smooth_scalable = TRUE;
else
bitmap_scalable = TRUE;
}
uint pixelSize = atoi( tokens[PixelSize] );
uint xpointSize = atoi( tokens[PointSize] );
uint xres = atoi( tokens[ResolutionX] );
uint yres = atoi( tokens[ResolutionY] );
uint avgwidth = atoi( tokens[AverageWidth] );
bool fixedPitch = isFixedPitch( tokens );
if (avgwidth == 0 && pixelSize != 0) {
/*
Ignore bitmap scalable fonts that are automatically
generated by some X servers. We know they are bitmap
scalable because even though they have a specified pixel
size, the average width is zero.
*/
continue;
}
QtFontFamily *family = fontFamily ? fontFamily : db->family( familyName, TRUE );
family->fontFileIndex = -1;
QtFontFoundry *foundry = family->foundry( foundryName, TRUE );
QtFontStyle *style = foundry->style( styleKey, TRUE );
delete [] style->weightName;
style->weightName = qstrdup( tokens[Weight] );
delete [] style->setwidthName;
style->setwidthName = qstrdup( tokens[Width] );
if ( smooth_scalable ) {
style->smoothScalable = TRUE;
style->bitmapScalable = FALSE;
pixelSize = SMOOTH_SCALABLE;
}
if ( !style->smoothScalable && bitmap_scalable )
style->bitmapScalable = TRUE;
if ( !fixedPitch )
family->fixedPitch = FALSE;
QtFontSize *size = style->pixelSize( pixelSize, TRUE );
QtFontEncoding *enc =
size->encodingID( encoding_id, xpointSize, xres, yres, avgwidth, TRUE );
enc->pitch = *tokens[Spacing];
if ( !enc->pitch ) enc->pitch = '*';
for ( int script = 0; script < QFont::LastPrivateScript; ++script ) {
if ( scripts_for_xlfd_encoding[encoding_id][script] )
family->scripts[script] = QtFontFamily::Supported;
else
family->scripts[script] |= QtFontFamily::UnSupported_Xlfd;
}
if ( encoding_id == -1 )
family->xlfdLoaded = TRUE;
}
if ( !reqFamily ) {
// mark encoding as loaded
if ( encoding_id == -1 )
xlfdsFullyLoaded = TRUE;
else
encodingLoaded[encoding_id] = TRUE;
}
XFreeFontNames( fontList );
#ifdef QT_XFT2
}
#endif // QT_XFT2
}
#ifndef QT_NO_XFTFREETYPE
static int getXftWeight(int xftweight)
{
int qtweight = QFont::Black;
if (xftweight <= (XFT_WEIGHT_LIGHT + XFT_WEIGHT_MEDIUM) / 2)
qtweight = QFont::Light;
else if (xftweight <= (XFT_WEIGHT_MEDIUM + XFT_WEIGHT_DEMIBOLD) / 2)
qtweight = QFont::Normal;
else if (xftweight <= (XFT_WEIGHT_DEMIBOLD + XFT_WEIGHT_BOLD) / 2)
qtweight = QFont::DemiBold;
else if (xftweight <= (XFT_WEIGHT_BOLD + XFT_WEIGHT_BLACK) / 2)
qtweight = QFont::Bold;
return qtweight;
}
static void loadXft()
{
if (!qt_has_xft)
return;
#ifdef QT_XFT2
struct XftDefaultFont {
const char *qtname;
const char *rawname;
bool fixed;
};
const XftDefaultFont defaults[] = {
{ "Serif", "serif", FALSE },
{ "Sans Serif", "sans-serif", FALSE },
{ "Monospace", "monospace", TRUE },
{ 0, 0, FALSE }
};
const XftDefaultFont *f = defaults;
while (f->qtname) {
QtFontFamily *family = db->family( f->qtname, TRUE );
family->fixedPitch = f->fixed;
family->rawName = f->rawname;
family->hasXft = TRUE;
family->synthetic = TRUE;
QtFontFoundry *foundry
= family->foundry( QString::null, TRUE );
for ( int i = 0; i < QFont::LastPrivateScript; ++i ) {
if (i == QFont::UnknownScript)
continue;
family->scripts[i] = QtFontFamily::Supported;
}
QtFontStyle::Key styleKey;
styleKey.oblique = FALSE;
for (int i = 0; i < 4; ++i) {
styleKey.italic = (i%2);
styleKey.weight = (i > 1) ? QFont::Bold : QFont::Normal;
QtFontStyle *style = foundry->style( styleKey, TRUE );
style->smoothScalable = TRUE;
QtFontSize *size = style->pixelSize( SMOOTH_SCALABLE, TRUE );
QtFontEncoding *enc = size->encodingID( -1, 0, 0, 0, 0, TRUE );
enc->pitch = (f->fixed ? 'm' : 'p');
}
++f;
}
#endif
}
#ifdef XFT_MATRIX
static void checkXftMatrix( QtFontFamily* family ) {
for ( int j = 0; j < family->count; ++j ) { // each foundry
QtFontFoundry *foundry = family->foundries[j];
for ( int k = 0; k < foundry->count; ++k ) {
QtFontStyle *style = foundry->styles[k];
if ( style->key.italic || style->key.oblique ) continue;
QtFontSize *size = style->pixelSize( SMOOTH_SCALABLE );
if ( ! size ) continue;
QtFontEncoding *enc = size->encodingID( -1, 0, 0, 0, 0, TRUE );
if ( ! enc ) continue;
QtFontStyle::Key key = style->key;
// does this style have an italic equivalent?
key.italic = TRUE;
QtFontStyle *equiv = foundry->style( key );
if ( equiv ) continue;
// does this style have an oblique equivalent?
key.italic = FALSE;
key.oblique = TRUE;
equiv = foundry->style( key );
if ( equiv ) continue;
// let's fake one...
equiv = foundry->style( key, TRUE );
equiv->fakeOblique = TRUE;
equiv->smoothScalable = TRUE;
QtFontSize *equiv_size = equiv->pixelSize( SMOOTH_SCALABLE, TRUE );
QtFontEncoding *equiv_enc = equiv_size->encodingID( -1, 0, 0, 0, 0, TRUE );
// keep the same pitch
equiv_enc->pitch = enc->pitch;
}
}
}
#endif // XFT_MATRIX
static bool loadXftFont( FcPattern* font )
{
QString familyName;
QString rawName;
char *value;
int weight_value;
int slant_value;
int spacing_value;
char *file_value;
int index_value;
char *foundry_value = 0;
FcBool scalable = FcTrue;
if (XftPatternGetString( font,
XFT_FAMILY, 0, &value) != XftResultMatch )
return false;
// capitalize( value );
rawName = familyName = QString::fromUtf8(value);
familyName.replace('-', ' ');
familyName.replace("/", "");
slant_value = XFT_SLANT_ROMAN;
weight_value = XFT_WEIGHT_MEDIUM;
spacing_value = XFT_PROPORTIONAL;
file_value = 0;
index_value = 0;
XftPatternGetInteger (font, XFT_SLANT, 0, &slant_value);
XftPatternGetInteger (font, XFT_WEIGHT, 0, &weight_value);
XftPatternGetInteger (font, XFT_SPACING, 0, &spacing_value);
XftPatternGetString (font, XFT_FILE, 0, &file_value);
XftPatternGetInteger (font, XFT_INDEX, 0, &index_value);
#ifdef QT_XFT2
FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
foundry_value = 0;
XftPatternGetString(font, FC_FOUNDRY, 0, &foundry_value);
#endif
QtFontFamily *family = db->family( familyName, TRUE );
family->rawName = rawName;
family->hasXft = TRUE;
#ifdef QT_XFT2
FcCharSet *charset = 0;
FcResult res = FcPatternGetCharSet(font, FC_CHARSET, 0, &charset);
if (res == FcResultMatch && FcCharSetCount(charset) > 1) {
for (int i = 0; i < QFont::LastPrivateScript; ++i) {
bool supported = sample_chars[i][0];
for (int j = 0; sample_chars[i][j]; ++j){
if (!FcCharSetHasChar(charset, sample_chars[i][j])) {
supported = false;
break;
}
}
if ( supported ){
family->scripts[i] = QtFontFamily::Supported;
} else {
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
}
}
family->xftScriptCheck = TRUE;
} else {
// we set UnknownScript to supported for symbol fonts. It makes no sense to merge these
// with other ones, as they are special in a way.
for ( int i = 0; i < QFont::LastPrivateScript; ++i )
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
family->scripts[QFont::UnknownScript] = QtFontFamily::Supported;
}
#endif // QT_XFT2
QCString file = (file_value ? file_value : "");
family->fontFilename = file;
family->fontFileIndex = index_value;
QtFontStyle::Key styleKey;
styleKey.italic = (slant_value == XFT_SLANT_ITALIC);
styleKey.oblique = (slant_value == XFT_SLANT_OBLIQUE);
styleKey.weight = getXftWeight( weight_value );
#ifdef QT_XFT2
if (!scalable) {
int width = 100;
#if FC_VERSION >= 20193
XftPatternGetInteger (font, FC_WIDTH, 0, &width);
#endif
styleKey.stretch = width;
}
#endif
QtFontFoundry *foundry
= family->foundry( foundry_value ? QString::fromUtf8(foundry_value) : QString::null, TRUE );
QtFontStyle *style = foundry->style( styleKey, TRUE );
if (spacing_value < XFT_MONO )
family->fixedPitch = FALSE;
QtFontSize *size;
if (scalable) {
style->smoothScalable = TRUE;
size = style->pixelSize( SMOOTH_SCALABLE, TRUE );
}
#ifdef QT_XFT2
else {
double pixel_size = 0;
XftPatternGetDouble (font, FC_PIXEL_SIZE, 0, &pixel_size);
size = style->pixelSize( (int)pixel_size, TRUE );
}
#endif
QtFontEncoding *enc = size->encodingID( -1, 0, 0, 0, 0, TRUE );
enc->pitch = ( spacing_value >= XFT_CHARCELL ? 'c' :
( spacing_value >= XFT_MONO ? 'm' : 'p' ) );
checkXftMatrix( family );
return true;
}
#ifndef QT_XFT2
#define MAKE_TAG( _x1, _x2, _x3, _x4 ) \
( ( (Q_UINT32)_x1 << 24 ) | \
( (Q_UINT32)_x2 << 16 ) | \
( (Q_UINT32)_x3 << 8 ) | \
(Q_UINT32)_x4 )
#ifdef _POSIX_MAPPED_FILES
static inline Q_UINT32 getUInt(unsigned char *p)
{
Q_UINT32 val;
val = *p++ << 24;
val |= *p++ << 16;
val |= *p++ << 8;
val |= *p;
return val;
}
static inline Q_UINT16 getUShort(unsigned char *p)
{
Q_UINT16 val;
val = *p++ << 8;
val |= *p;
return val;
}
static inline void tag_to_string( char *string, Q_UINT32 tag )
{
string[0] = (tag >> 24)&0xff;
string[1] = (tag >> 16)&0xff;
string[2] = (tag >> 8)&0xff;
string[3] = tag&0xff;
string[4] = 0;
}
static Q_UINT16 getGlyphIndex( unsigned char *table, Q_UINT16 format, unsigned short unicode )
{
if ( format == 0 ) {
if ( unicode < 256 )
return (int) *(table+6+unicode);
} else if ( format == 2 ) {
qWarning("format 2 encoding table for Unicode, not implemented!");
} else if ( format == 4 ) {
Q_UINT16 segCountX2 = getUShort( table + 6 );
unsigned char *ends = table + 14;
Q_UINT16 endIndex = 0;
int i = 0;
for ( ; i < segCountX2/2 && (endIndex = getUShort( ends + 2*i )) < unicode; i++ );
unsigned char *idx = ends + segCountX2 + 2 + 2*i;
Q_UINT16 startIndex = getUShort( idx );
if ( startIndex > unicode )
return 0;
idx += segCountX2;
Q_INT16 idDelta = (Q_INT16)getUShort( idx );
idx += segCountX2;
Q_UINT16 idRangeoffset_t = (Q_UINT16)getUShort( idx );
Q_UINT16 glyphIndex;
if ( idRangeoffset_t ) {
Q_UINT16 id = getUShort( idRangeoffset_t + 2*(unicode - startIndex) + idx);
if ( id )
glyphIndex = ( idDelta + id ) % 0x10000;
else
glyphIndex = 0;
} else {
glyphIndex = (idDelta + unicode) % 0x10000;
}
return glyphIndex;
}
return 0;
}
#endif // _POSIX_MAPPED_FILES
static inline void checkXftCoverage( QtFontFamily *family )
{
#ifdef _POSIX_MAPPED_FILES
QCString ext = family->fontFilename.mid( family->fontFilename.findRev( '.' ) ).lower();
if ( family->fontFileIndex == 0 && ( ext == ".ttf" || ext == ".otf" ) ) {
void *map;
// qDebug("using own ttf code coverage checking of '%s'!", family->name.latin1() );
int fd = open( family->fontFilename.data(), O_RDONLY );
size_t pagesize = getpagesize();
off_t offset = 0;
size_t length = (8192 / pagesize + 1) * pagesize;
if ( fd == -1 )
goto xftCheck;
{
if ( (map = mmap( 0, length, PROT_READ, MAP_SHARED, fd, offset ) ) == MAP_FAILED )
goto error;
unsigned char *ttf = (unsigned char *)map;
Q_UINT32 version = getUInt( ttf );
if ( version != 0x00010000 ) {
// qDebug("file has wrong version %x", version );
goto error1;
}
Q_UINT16 numTables = getUShort( ttf+4 );
unsigned char *table_dir = ttf + 12;
Q_UINT32 cmap_offset = 0;
Q_UINT32 cmap_length = 0;
for ( int n = 0; n < numTables; n++ ) {
Q_UINT32 tag = getUInt( table_dir + 16*n );
if ( tag == MAKE_TAG( 'c', 'm', 'a', 'p' ) ) {
cmap_offset = getUInt( table_dir + 16*n + 8 );
cmap_length = getUInt( table_dir + 16*n + 12 );
break;
}
}
if ( !cmap_offset ) {
// qDebug("no cmap found" );
goto error1;
}
if ( cmap_offset + cmap_length > length ) {
munmap( map, length );
offset = cmap_offset / pagesize * pagesize;
cmap_offset -= offset;
length = (cmap_offset + cmap_length);
if ( (map = mmap( 0, length, PROT_READ, MAP_SHARED, fd, offset ) ) == MAP_FAILED )
goto error;
}
unsigned char *cmap = ((unsigned char *)map) + cmap_offset;
version = getUShort( cmap );
if ( version != 0 ) {
// qDebug("wrong cmap version" );
goto error1;
}
numTables = getUShort( cmap + 2 );
unsigned char *unicode_table = 0;
bool symbol_table = TRUE;
for ( int n = 0; n < numTables; n++ ) {
Q_UINT32 version = getUInt( cmap + 4 + 8*n );
// accept both symbol and Unicode encodings. prefer unicode.
if ( version == 0x00030001 || version == 0x00030000 ) {
unicode_table = cmap + getUInt( cmap + 4 + 8*n + 4 );
if ( version == 0x00030001 ) {
symbol_table = FALSE;
break;
}
}
}
if ( !unicode_table ) {
// qDebug("no unicode table found" );
goto error1;
}
Q_UINT16 format = getUShort( unicode_table );
if ( format != 4 )
goto error1;
if (symbol_table) {
// we set UnknownScript to supported for symbol fonts. It makes no sense to merge these
// with other ones, as they are special in a way.
for ( int i = 0; i < QFont::LastPrivateScript; ++i )
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
family->scripts[QFont::UnknownScript] = QtFontFamily::Supported;
} else {
for ( int i = 0; i < QFont::LastPrivateScript; ++i ) {
bool supported = sample_chars[i][0];
for (int j = 0; sample_chars[i][j]; ++j) {
if (!getGlyphIndex(unicode_table, format, sample_chars[i][j])) {
supported=false;
break;
}
}
if ( supported ){
// qDebug("font can render script %d", i );
family->scripts[i] = QtFontFamily::Supported;
} else {
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
}
}
}
family->xftScriptCheck = TRUE;
}
error1:
munmap( map, length );
error:
close( fd );
if ( family->xftScriptCheck )
return;
}
xftCheck:
#endif // _POSIX_MAPPED_FILES
FD_DEBUG("using Freetype for checking of '%s'", family->name.latin1() );
FT_Library ft_lib;
FT_Error error = FT_Init_FreeType( &ft_lib );
if ( error ) return;
FT_Face face;
error = FT_New_Face( ft_lib, family->fontFilename, family->fontFileIndex, &face );
if ( error ) return;
for ( int i = 0; i < QFont::LastPrivateScript; ++i ) {
bool supported = sample_chars[i][j];
for (int j = 0; sample_chars[i][j]; ++j){
if (!FT_Get_Char_Index(face, sample_chars[i][j])) {
supported=false;
break;
}
}
if ( supported ){
FD_DEBUG("font can render char %04x, %04x script %d '%s'",
ch.unicode(), FT_Get_Char_Index ( face, ch.unicode() ),
i, QFontDatabase::scriptName( (QFont::Script)i ).latin1() );
family->scripts[i] = QtFontFamily::Supported;
} else {
family->scripts[i] |= QtFontFamily::UnSupported_Xft;
}
}
FT_Done_Face( face );
FT_Done_FreeType( ft_lib );
family->xftScriptCheck = TRUE;
}
#endif // QT_XFT2
#endif // QT_NO_XFTFREETYPE
static void load( const QString &family = QString::null, int script = -1 )
{
#ifdef QFONTDATABASE_DEBUG
QTime t;
t.start();
#endif
if ( family.isNull() ) {
#ifndef QT_NO_XFTFREETYPE
static bool xft_readall_done = false;
if (qt_has_xft && !xft_readall_done) {
xft_readall_done = true;
XftFontSet *fonts =
XftListFonts(QPaintDevice::x11AppDisplay(),
QPaintDevice::x11AppScreen(),
(const char *)0,
XFT_FAMILY, XFT_WEIGHT, XFT_SLANT,
XFT_SPACING, XFT_FILE, XFT_INDEX,
#ifdef QT_XFT2
FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE,
#if FC_VERSION >= 20193
FC_WIDTH,
#endif
#endif // QT_XFT2
(const char *)0);
for (int i = 0; i < fonts->nfont; i++)
loadXftFont( fonts->fonts[i] );
XftFontSetDestroy (fonts);
}
#ifdef QT_XFT2
if (qt_has_xft)
return;
#endif
#endif // QT_NO_XFTFREETYPE
if ( script == -1 )
loadXlfds( 0, -1 );
else {
for ( int i = 0; i < numEncodings; i++ ) {
if ( scripts_for_xlfd_encoding[i][script] )
loadXlfds( 0, i );
}
}
} else {
QtFontFamily *f = db->family( family, TRUE );
if ( !f->fullyLoaded ) {
#ifndef QT_NO_XFTFREETYPE
if (qt_has_xft) {
QString mfamily = family;
redo:
XftFontSet *fonts =
XftListFonts(QPaintDevice::x11AppDisplay(),
QPaintDevice::x11AppScreen(),
XFT_FAMILY, XftTypeString, mfamily.utf8().data(),
(const char *)0,
XFT_FAMILY, XFT_WEIGHT, XFT_SLANT,
XFT_SPACING, XFT_FILE, XFT_INDEX,
#ifdef QT_XFT2
FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE,
#if FC_VERSION >= 20193
FC_WIDTH,
#endif
#endif // QT_XFT2
(const char *)0);
for (int i = 0; i < fonts->nfont; i++)
loadXftFont( fonts->fonts[i] );
XftFontSetDestroy (fonts);
if (mfamily.contains(' ')) {
mfamily.replace(QChar(' '), QChar('-'));
goto redo;
}
f->fullyLoaded = TRUE;
#ifdef QT_XFT2
return;
#endif
}
#ifndef QT_XFT2
// need to check Xft coverage
if ( f->hasXft && !f->xftScriptCheck ) {
checkXftCoverage( f );
}
#endif
#endif // QT_NO_XFTFREETYPE
// could reduce this further with some more magic:
// would need to remember the encodings loaded for the family.
if ( ( script == -1 && !f->xlfdLoaded ) ||
( !f->hasXft && !(f->scripts[script] & QtFontFamily::Supported) &&
!(f->scripts[script] & QtFontFamily::UnSupported_Xlfd) ) ) {
loadXlfds( family, -1 );
f->fullyLoaded = TRUE;
}
}
}
#ifdef QFONTDATABASE_DEBUG
FD_DEBUG("QFontDatabase: load( %s, %d) took %d ms", family.latin1(), script, t.elapsed() );
#endif
}
static void initializeDb()
{
if ( db ) return;
db = new QFontDatabasePrivate;
qfontdatabase_cleanup.set(&db);
#ifndef QT_XFT2
memset( encodingLoaded, FALSE, sizeof( encodingLoaded ) );
#endif
QTime t;
t.start();
#ifndef QT_NO_XFTFREETYPE
loadXft();
FD_DEBUG("QFontDatabase: loaded Xft: %d ms", t.elapsed() );
#endif
t.start();
#ifndef QT_NO_XFTFREETYPE
for ( int i = 0; i < db->count; i++ ) {
#ifndef QT_XFT2
checkXftCoverage( db->families[i] );
FD_DEBUG("QFontDatabase: xft coverage check: %d ms", t.elapsed() );
#endif // QT_XFT2
#ifdef XFT_MATRIX
checkXftMatrix( db->families[i] );
#endif // XFT_MATRIX
}
#endif
#ifdef QFONTDATABASE_DEBUG
#ifdef QT_XFT2
if (!qt_has_xft)
#endif
// load everything at startup in debug mode.
loadXlfds( 0, -1 );
// print the database
for ( int f = 0; f < db->count; f++ ) {
QtFontFamily *family = db->families[f];
FD_DEBUG("'%s' %s hasXft=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
(family->hasXft ? "yes" : "no") );
for ( int i = 0; i < QFont::LastPrivateScript; ++i ) {
FD_DEBUG("\t%s: %s", QFontDatabase::scriptName((QFont::Script) i).latin1(),
((family->scripts[i] & QtFontFamily::Supported) ? "Supported" :
(family->scripts[i] & QtFontFamily::UnSupported) == QtFontFamily::UnSupported ?
"UnSupported" : "Unknown"));
}
for ( int fd = 0; fd < family->count; fd++ ) {
QtFontFoundry *foundry = family->foundries[fd];
FD_DEBUG("\t\t'%s'", foundry->name.latin1() );
for ( int s = 0; s < foundry->count; s++ ) {
QtFontStyle *style = foundry->styles[s];
FD_DEBUG("\t\t\tstyle: italic=%d oblique=%d (fake=%d) weight=%d (%s)\n"
"\t\t\tstretch=%d (%s)",
style->key.italic, style->key.oblique, style->fakeOblique, style->key.weight,
style->weightName, style->key.stretch,
style->setwidthName ? style->setwidthName : "nil" );
if ( style->smoothScalable )
FD_DEBUG("\t\t\t\tsmooth scalable" );
else if ( style->bitmapScalable )
FD_DEBUG("\t\t\t\tbitmap scalable" );
if ( style->pixelSizes ) {
qDebug("\t\t\t\t%d pixel sizes", style->count );
for ( int z = 0; z < style->count; ++z ) {
QtFontSize *size = style->pixelSizes + z;
for ( int e = 0; e < size->count; ++e ) {
FD_DEBUG( "\t\t\t\t size %5d pitch %c encoding %s",
size->pixelSize,
size->encodings[e].pitch,
xlfd_for_id( size->encodings[e].encoding ) );
}
}
}
}
}
}
#endif // QFONTDATABASE_DEBUG
}
void QFontDatabase::createDatabase()
{
initializeDb();
}
// --------------------------------------------------------------------------------------
// font loader
// --------------------------------------------------------------------------------------
#define MAXFONTSIZE_XFT 256
#define MAXFONTSIZE_XLFD 128
#ifndef QT_NO_XFTFREETYPE
static double addPatternProps(XftPattern *pattern, const QtFontStyle::Key &key, bool fakeOblique,
bool smoothScalable, const QFontPrivate *fp, const QFontDef &request)
{
int weight_value = XFT_WEIGHT_BLACK;
if ( key.weight == 0 )
weight_value = XFT_WEIGHT_MEDIUM;
else if ( key.weight < (QFont::Light + QFont::Normal) / 2 )
weight_value = XFT_WEIGHT_LIGHT;
else if ( key.weight < (QFont::Normal + QFont::DemiBold) / 2 )
weight_value = XFT_WEIGHT_MEDIUM;
else if ( key.weight < (QFont::DemiBold + QFont::Bold) / 2 )
weight_value = XFT_WEIGHT_DEMIBOLD;
else if ( key.weight < (QFont::Bold + QFont::Black) / 2 )
weight_value = XFT_WEIGHT_BOLD;
XftPatternAddInteger( pattern, XFT_WEIGHT, weight_value );
int slant_value = XFT_SLANT_ROMAN;
if ( key.italic )
slant_value = XFT_SLANT_ITALIC;
else if ( key.oblique && !fakeOblique )
slant_value = XFT_SLANT_OBLIQUE;
XftPatternAddInteger( pattern, XFT_SLANT, slant_value );
/*
Xft1 doesn't obey user settings for turning off anti-aliasing using
the following:
match any size > 6 size < 12 edit antialias = false;
... if we request pixel sizes. so, work around this limitiation and
convert the pixel size to a point size and request that.
*/
double size_value = request.pixelSize;
double dpi = QPaintDevice::x11AppDpiY(fp->screen);
double scale = 1.;
if ( size_value > MAXFONTSIZE_XFT ) {
scale = (double)size_value/(double)MAXFONTSIZE_XFT;
size_value = MAXFONTSIZE_XFT;
}
#ifdef QT_XFT2
/*
2006-12-28 If QT is not compiled against xft1, there is no need
for the workaround above (confirmed). Thus, in addition, add
font pixelsize to the pattern to avoid fontconfig making wrong
guesses. Also provide a DPI value for fontconfig so it never
attempts to fallback to its default.
*/
XftPatternAddDouble(pattern, XFT_PIXEL_SIZE, size_value);
XftPatternAddDouble(pattern, XFT_DPI, dpi);
#endif
size_value = size_value*72./dpi;
XftPatternAddDouble( pattern, XFT_SIZE, size_value );
#ifdef XFT_MATRIX
# ifdef QT_XFT2
if (!smoothScalable) {
# if FC_VERSION >= 20193
int stretch = request.stretch;
if (!stretch)
stretch = 100;
XftPatternAddInteger(pattern, FC_WIDTH, stretch);
# endif
} else
# endif
if ( ( request.stretch > 0 && request.stretch != 100 ) ||
( key.oblique && fakeOblique ) ) {
XftMatrix matrix;
XftMatrixInit( &matrix );
if ( request.stretch > 0 && request.stretch != 100 )
XftMatrixScale( &matrix, double( request.stretch ) / 100.0, 1.0 );
if ( key.oblique && fakeOblique )
XftMatrixShear( &matrix, 0.20, 0.0 );
XftPatternAddMatrix( pattern, XFT_MATRIX, &matrix );
}
#endif // XFT_MATRIX
if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
XftPatternDel(pattern, XFT_ANTIALIAS);
XftPatternAddBool(pattern, XFT_ANTIALIAS,
!(request.styleStrategy & QFont::NoAntialias));
}
return scale;
}
#endif // QT_NO_XFTFREETYPE
static
QFontEngine *loadEngine( QFont::Script script,
const QFontPrivate *fp, const QFontDef &request,
QtFontFamily *family, QtFontFoundry *foundry,
QtFontStyle *style, QtFontSize *size,
QtFontEncoding *encoding, bool forced_encoding )
{
Q_UNUSED(script);
if ( fp && fp->rawMode ) {
QCString xlfd = request.family.latin1();
FM_DEBUG( "Loading XLFD (rawmode) '%s'", xlfd.data() );
XFontStruct *xfs;
if (! (xfs = XLoadQueryFont(QPaintDevice::x11AppDisplay(), xlfd.data() ) ) )
return 0;
QFontEngine *fe = new QFontEngineXLFD( xfs, xlfd.data(), 0 );
if ( ! qt_fillFontDef( xfs, &fe->fontDef, QPaintDevice::x11AppScreen() ) &&
! qt_fillFontDef( xlfd, &fe->fontDef, QPaintDevice::x11AppScreen() ) )
fe->fontDef = QFontDef();
return fe;
}
#ifndef QT_NO_XFTFREETYPE
if ( encoding->encoding == -1 ) {
FM_DEBUG( " using Xft" );
XftPattern *pattern = XftPatternCreate();
if ( !pattern ) return 0;
bool symbol = (family->scripts[QFont::UnknownScript] == QtFontFamily::Supported);
# ifdef QT_XFT2
if (!symbol && script != QFont::Unicode) {
FcCharSet *cs = FcCharSetCreate();
for ( int j=0; sample_chars[script][j]; j++ )
FcCharSetAddChar(cs, sample_chars[script][j]);
if (script == QFont::Latin)
// add Euro character
FcCharSetAddChar(cs, 0x20ac);
FcPatternAddCharSet(pattern, FC_CHARSET, cs);
FcCharSetDestroy(cs);
}
# else
XftPatternAddString( pattern, XFT_ENCODING, symbol ? "adobe-fontspecific" : "iso10646-1");
# endif // QT_XFT2
if ( !foundry->name.isEmpty() )
XftPatternAddString( pattern, XFT_FOUNDRY,
foundry->name.utf8().data() );
if ( !family->rawName.isEmpty() )
XftPatternAddString( pattern, XFT_FAMILY,
family->rawName.utf8().data() );
char pitch_value = ( encoding->pitch == 'c' ? XFT_CHARCELL :
( encoding->pitch == 'm' ? XFT_MONO : XFT_PROPORTIONAL ) );
XftPatternAddInteger( pattern, XFT_SPACING, pitch_value );
double scale = addPatternProps(pattern, style->key, style->fakeOblique,
style->smoothScalable, fp, request);
XftResult res;
XftPattern *result =
XftFontMatch( QPaintDevice::x11AppDisplay(), fp->screen, pattern, &res );
#ifdef QT_XFT2
if (result && script == QFont::Latin) {
// since we added the Euro char on top, check we actually got the family
// we requested. If we didn't get it correctly, remove the Euro from the pattern
// and try again.
FcChar8 *f;
res = FcPatternGetString(result, FC_FAMILY, 0, &f);
if (res == FcResultMatch && QString::fromUtf8((char *)f) != family->rawName) {
FcPatternDel(pattern, FC_CHARSET);
FcCharSet *cs = FcCharSetCreate();
for ( int j=0; sample_chars[script][j]; j++ )
FcCharSetAddChar(cs, sample_chars[script][j]);
FcPatternAddCharSet(pattern, FC_CHARSET, cs);
FcCharSetDestroy(cs);
result = XftFontMatch( QPaintDevice::x11AppDisplay(), fp->screen, pattern, &res );
}
}
#endif
XftPatternDestroy(pattern);
if (!result)
return 0;
// somehow this gets lost in the XftMatch call, reset the anitaliasing property correctly.
if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
XftPatternDel(result, XFT_ANTIALIAS);
XftPatternAddBool(result, XFT_ANTIALIAS,
!(request.styleStrategy & QFont::NoAntialias));
}
// We pass a duplicate to XftFontOpenPattern because either xft font
// will own the pattern after the call or the pattern will be
// destroyed.
XftPattern *dup = XftPatternDuplicate( result );
XftFont *xftfs = XftFontOpenPattern( QPaintDevice::x11AppDisplay(), dup );
if ( ! xftfs ) // Xft couldn't find a font?
return 0;
QFontEngine *fe = new QFontEngineXft( xftfs, result, symbol ? 1 : 0 );
if (fp->paintdevice
&& QPaintDeviceMetrics(fp->paintdevice).logicalDpiY() != QPaintDevice::x11AppDpiY()) {
double px;
XftPatternGetDouble(result, XFT_PIXEL_SIZE, 0, &px);
scale = (double)request.pixelSize/px;
}
fe->setScale( scale );
return fe;
}
#endif // QT_NO_XFTFREETYPE
FM_DEBUG( " using XLFD" );
QCString xlfd = "-";
xlfd += foundry->name.isEmpty() ? "*" : foundry->name.latin1();
xlfd += "-";
xlfd += family->name.isEmpty() ? "*" : family->name.latin1();
xlfd += "-";
xlfd += style->weightName ? style->weightName : "*";
xlfd += "-";
xlfd += ( style->key.italic ? "i" : ( style->key.oblique ? "o" : "r" ) );
xlfd += "-";
xlfd += style->setwidthName ? style->setwidthName : "*";
// ### handle add-style
xlfd += "-*-";
int px = size->pixelSize;
if ( style->smoothScalable && px == SMOOTH_SCALABLE )
px = request.pixelSize;
else if ( style->bitmapScalable && px == 0 )
px = request.pixelSize;
double scale = 1.;
if ( px > MAXFONTSIZE_XLFD ) {
scale = (double)px/(double)MAXFONTSIZE_XLFD;
px = MAXFONTSIZE_XLFD;
}
if (fp && fp->paintdevice
&& QPaintDeviceMetrics(fp->paintdevice).logicalDpiY() != QPaintDevice::x11AppDpiY())
scale = (double)request.pixelSize/(double)px;
xlfd += QString::number( px ).latin1();
xlfd += "-";
xlfd += QString::number( encoding->xpoint );
xlfd += "-";
xlfd += QString::number( encoding->xres );
xlfd += "-";
xlfd += QString::number( encoding->yres );
xlfd += "-";
// ### handle cell spaced fonts
xlfd += encoding->pitch;
xlfd += "-";
xlfd += QString::number( encoding->avgwidth );
xlfd += "-";
xlfd += xlfd_for_id( encoding->encoding );
FM_DEBUG( " xlfd: '%s'", xlfd.data() );
XFontStruct *xfs;
if (! (xfs = XLoadQueryFont(QPaintDevice::x11AppDisplay(), xlfd.data() ) ) )
return 0;
QFontEngine *fe = 0;
const int mib = xlfd_encoding[ encoding->encoding ].mib;
if (script == QFont::Latin && encoding->encoding <= LAST_LATIN_ENCODING && !forced_encoding) {
fe = new QFontEngineLatinXLFD( xfs, xlfd.data(), mib );
} else {
fe = new QFontEngineXLFD( xfs, xlfd.data(), mib );
}
fe->setScale( scale );
return fe;
}
#ifdef QT_XFT2
static void parseFontName(const QString &name, QString &foundry, QString &family)
{
if ( name.contains('[') && name.contains(']')) {
int i = name.find('[');
int li = name.findRev(']');
if (i < li) {
foundry = name.mid(i + 1, li - i - 1);
if (name[i - 1] == ' ')
i--;
family = name.left(i);
}
} else {
foundry = QString::null;
family = name;
}
}
static QFontEngine *loadFontConfigFont(const QFontPrivate *fp, const QFontDef &request, QFont::Script script)
{
if (!qt_has_xft)
return 0;
QStringList family_list;
if (request.family.isEmpty()) {
family_list = QStringList::split(QChar(','), fp->request.family);
QString stylehint;
switch ( request.styleHint ) {
case QFont::SansSerif:
stylehint = "sans-serif";
break;
case QFont::Serif:
stylehint = "serif";
break;
case QFont::TypeWriter:
stylehint = "monospace";
break;
default:
if (request.fixedPitch)
stylehint = "monospace";
break;
}
if (!stylehint.isEmpty())
family_list << stylehint;
} else {
family_list << request.family;
}
FcPattern *pattern = FcPatternCreate();
{
QString family, foundry;
for (QStringList::ConstIterator it = family_list.begin(); it != family_list.end(); ++it) {
parseFontName(*it, foundry, family);
XftPatternAddString(pattern, XFT_FAMILY, family.utf8().data());
}
}
QtFontStyle::Key key;
key.italic = request.italic;
key.weight = request.weight;
key.stretch = request.stretch;
double scale = addPatternProps(pattern, key, FALSE, TRUE, fp, request);
#ifdef FONT_MATCH_DEBUG
qDebug("original pattern contains:");
FcPatternPrint(pattern);
#endif
// XftFontMatch calls the right ConfigSubstitute variants, but as we use
// FcFontMatch/Sort here we have to do it manually.
FcConfigSubstitute(0, pattern, FcMatchPattern);
XftDefaultSubstitute(QPaintDevice::x11AppDisplay(), QPaintDevice::x11AppScreen(), pattern);
// qDebug("1: pattern contains:");
// FcPatternPrint(pattern);
{
FcValue value;
value.type = FcTypeString;
// these should only get added to the pattern _after_ substitution
// append the default fallback font for the specified script
extern QString qt_fallback_font_family( QFont::Script );
QString fallback = qt_fallback_font_family( script );
if ( ! fallback.isEmpty() && ! family_list.contains( fallback ) ) {
QCString cs = fallback.utf8();
value.u.s = (const FcChar8 *)cs.data();
FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
}
// add the default family
QString defaultFamily = QApplication::font().family();
if ( ! family_list.contains( defaultFamily ) ) {
QCString cs = defaultFamily.utf8();
value.u.s = (const FcChar8 *)cs.data();
FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
}
// add QFont::defaultFamily() to the list, for compatibility with
// previous versions
defaultFamily = QApplication::font().defaultFamily();
if ( ! family_list.contains( defaultFamily ) ) {
QCString cs = defaultFamily.utf8();
value.u.s = (const FcChar8 *)cs.data();
FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
}
}
if (script != QFont::Unicode) {
FcCharSet *cs = FcCharSetCreate();
for ( int j=0; sample_chars[script][j]; j++ )
FcCharSetAddChar(cs, sample_chars[script][j]);
if (script == QFont::Latin)
// add Euro character
FcCharSetAddChar(cs, 0x20ac);
FcPatternAddCharSet(pattern, FC_CHARSET, cs);
FcCharSetDestroy(cs);
}
#ifdef FONT_MATCH_DEBUG
printf("final pattern contains:\n");
FcPatternPrint(pattern);
#endif
QFontEngine *fe = 0;
for( int jj = (FcGetVersion() >= 20392 ? 0 : 1); jj < 2; ++jj ) {
bool use_fontsort = ( jj == 1 );
FcResult result;
FcFontSet *fs = 0;
FcPattern *fsp = 0;
// Properly conform to fontconfig API. We need to call FcDefaultSubstitute()
// before FcFontSort()/FcFontMatch().
FcDefaultSubstitute(pattern);
if( use_fontsort ) {
fs = FcFontSort(0, pattern, FcFalse, 0, &result);
if (!fs)
continue;
} else {
fsp = FcFontMatch(0, pattern, &result);
if (!fsp)
continue;
}
#ifdef FONT_MATCH_DEBUG
if( use_fontsort ) {
printf("fontset contains:\n");
for (int i = 0; i < fs->nfont; ++i) {
FcPattern *test = fs->fonts[i];
FcChar8 *fam;
FcPatternGetString(test, FC_FAMILY, 0, &fam);
printf(" %s\n", fam);
}
} else {
printf("fontmatch:");
FcChar8 *fam;
FcPatternGetString(fsp, FC_FAMILY, 0, &fam);
printf(" %s\n", fam);
}
#endif
double size_value = request.pixelSize;
if ( size_value > MAXFONTSIZE_XFT )
size_value = MAXFONTSIZE_XFT;
int cnt = use_fontsort ? fs->nfont : 1;
for (int i = 0; i < cnt; ++i) {
FcPattern *font = use_fontsort ? fs->fonts[i] : fsp;
FcCharSet *cs;
FcResult res = FcPatternGetCharSet(font, FC_CHARSET, 0, &cs);
if (res != FcResultMatch)
continue;
bool do_break=true;
for ( int j=0; sample_chars[script][j]; j++ ){
do_break=false;
if (!FcCharSetHasChar(cs, sample_chars[script][j])) {
do_break=true;
break;
}
}
if ( do_break )
continue;
FcBool scalable;
res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
if (res != FcResultMatch || !scalable) {
int pixelSize;
res = FcPatternGetInteger(font, FC_PIXEL_SIZE, 0, &pixelSize);
if (res != FcResultMatch || QABS((size_value-pixelSize)/size_value) > 0.2)
continue;
}
XftPattern *pattern = XftPatternDuplicate(font);
// add properties back in as the font selected from the list doesn't contain them.
addPatternProps(pattern, key, FALSE, TRUE, fp, request);
XftPattern *result =
XftFontMatch( QPaintDevice::x11AppDisplay(), fp->screen, pattern, &res );
XftPatternDestroy(pattern);
// We pass a duplicate to XftFontOpenPattern because either xft font
// will own the pattern after the call or the pattern will be
// destroyed.
XftPattern *dup = XftPatternDuplicate( result );
XftFont *xftfs = XftFontOpenPattern( QPaintDevice::x11AppDisplay(), dup );
if ( !xftfs ) {
// Xft couldn't find a font?
qDebug("couldn't open fontconfigs chosen font with Xft!!!");
} else {
fe = new QFontEngineXft( xftfs, result, 0 );
if (fp->paintdevice
&& QPaintDeviceMetrics(fp->paintdevice).logicalDpiY() != QPaintDevice::x11AppDpiY()) {
double px;
XftPatternGetDouble(result, XFT_PIXEL_SIZE, 0, &px);
scale = request.pixelSize/px;
}
fe->setScale( scale );
fe->fontDef = request;
if ( script != QFont::Unicode && !canRender(fe, script) ) {
FM_DEBUG( " WARN: font loaded cannot render samples" );
delete fe;
fe = 0;
}else
FM_DEBUG( " USE: %s", fe->fontDef.family.latin1() );
}
if (fe) {
QFontEngineXft *xft = (QFontEngineXft *)fe;
char *family;
if (XftPatternGetString(xft->pattern(), XFT_FAMILY, 0, &family) == XftResultMatch)
xft->fontDef.family = QString::fromUtf8(family);
double px;
if (XftPatternGetDouble(xft->pattern(), XFT_PIXEL_SIZE, 0, &px) == XftResultMatch)
xft->fontDef.pixelSize = qRound(px);
int weight = XFT_WEIGHT_MEDIUM;
XftPatternGetInteger(xft->pattern(), XFT_WEIGHT, 0, &weight);
xft->fontDef.weight = getXftWeight(weight);
int slant = XFT_SLANT_ROMAN;
XftPatternGetInteger(xft->pattern(), XFT_SLANT, 0, &slant);
xft->fontDef.italic = (slant != XFT_SLANT_ROMAN);
int spacing = XFT_PROPORTIONAL;
XftPatternGetInteger(xft->pattern(), XFT_SPACING, 0, &spacing);
xft->fontDef.fixedPitch = spacing != XFT_PROPORTIONAL;
xft->fontDef.ignorePitch = FALSE;
break;
}
}
if( use_fontsort )
FcFontSetDestroy(fs);
else
FcPatternDestroy(fsp);
if( fe )
break;
} // for( jj )
FcPatternDestroy(pattern);
return fe;
}
#endif