1. 程式人生 > >Qt5.6.1如何使用qpf2字型

Qt5.6.1如何使用qpf2字型

最近在移植Qt到一個商用的小眾系統上,Qt版本是Qt5.6.1,Qt是不支援這個系統的,在移植過程中遇到了很多的問題,這裡對字型移植遇的問題進行一下記錄。(這個辦法是可以使用qpf2字型的,但是是不是最好的辦法還不知道,希望可以幫助到需要的人,也希望有人一起討論)

1.問題:

  首先是報找不到字型,當字型的路徑設定正確後。程式在呼叫setText相關方法的時候,整個系統就會dump掉,這個系統經常用dump,記憶體分配上可能有一些問題。如果字型的路徑設定不正確系統倒是可以正確執行,最後經過查詢程式碼和參考網上的經驗決定使用qpf字型(優點就是省去了Qt解析字型這個過程,佔用記憶體小(我懷疑係統dump是存上有問題),缺點是qpf字型字號大小是固定的,他是一個二進位制的檔案)。

2.進展:

  Qt  Help文件說明Qt是支援qpf字型的,在Qt4版本之後支援qpf2字型。把字型檔下的所有字型刪除只留下qpf2字型還是沒有辦法顯示(在PC機上和目標板上嘗試都是不可以的)。在網上查到資料說是Qt5雖然說是支援qpf2,但是實際上是個BUG,實現根本不支援(我檢視程式碼後發現,是一個虛擬函式,當呼叫子類的方法時就不支援qpf2,當呼叫父類的方法時就支援qpf2,下面會說一下這個問題),沒有找到解決辦法。

於是檢視原始碼和PC跟蹤程式執行過程。

3.解決:

  在字型相關初始化的過程中會呼叫qt-everywhere-opensource-src-5.6.1\qtbase\src\platformsupport\fontdatabases\fontconfig\qfontconfigdatabase.cpp檔案中的

initializeDb()方法

原始碼如下:

static void initializeDb()

{

   QFontDatabasePrivate *db = privateDb();

 

   // init by asking for the platformfontdb for the first time or afterinvalidation

   if (!db->count)

       QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();

 

   if (db->reregisterAppFonts) {

       for (int i = 0; i < db->applicationFonts.count(); i++) {

           if (!db->applicationFonts.at(i).families.isEmpty())

               registerFont(&db->applicationFonts[i]);

       }

       db->reregisterAppFonts = false;

    }

}

populateFontDatabase()這個方法有兩處實現分別見下面的原始碼,而initializeDb()方法中呼叫的實際是populateFontDatabase();方法實現際呼叫的是QBasicFontDatabase類中實現的。

qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp中

qtbase/src/gui/text/qplatformfontdatabase.cpp中

 

在類QBasicFontDatabase定義中可以看到QBasicFontDatabase是QPlatformFontDatabase子類

class QBasicFontDatabase : publicQPlatformFontDatabase

{

public:

//   void populateFontDatabase() Q_DECL_OVERRIDE;  //change on_ose

/*   QFontEngine *fontEngine(const QFontDef &fontDef, void *handle)Q_DECL_OVERRIDE;

   QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize,QFont::HintingPreference hintingPreference) Q_DECL_OVERRIDE;

   QStringList addApplicationFont(const QByteArray &fontData, constQString &fileName) Q_DECL_OVERRIDE;

   void releaseHandle(void *handle) Q_DECL_OVERRIDE;

 

   static QStringList addTTFile(const QByteArray &fontData, constQByteArray &file);

*/

};

下面給出QBasicFontDatabase和QPlatformFontDatabase類中populateFontDatabase()方法的實現:

1.

voidQBasicFontDatabase::populateFontDatabase()

{

   QString fontpath = fontDir();

   QDir dir(fontpath);

 

   if (!dir.exists()) {

       qWarning("QFontDatabase: Cannot find font directory %s - is Qtinstalled correctly?",

               qPrintable(fontpath));

       return;

    }

 

   QStringList nameFilters;

   nameFilters << QLatin1String("*.ttf")

                << QLatin1String("*.ttc")

                <<QLatin1String("*.pfa")

                <<QLatin1String("*.pfb")

                <<QLatin1String("*.otf");

 

   foreach (const QFileInfo &fi, dir.entryInfoList(nameFilters,QDir::Files)) {

       const QByteArray file = QFile::encodeName(fi.absoluteFilePath());

       QBasicFontDatabase::addTTFile(QByteArray(), file);

    }

}

2.

voidQPlatformFontDatabase::populateFontDatabase()

{

   QString fontpath = fontDir();

   if(!QFile::exists(fontpath)) {

       qWarning("QFontDatabase: Cannot find font directory '%s' - is Qtinstalled correctly?",

                qPrintable(QDir::toNativeSeparators(fontpath)));

       return;

    }

 

   QDir dir(fontpath);

   dir.setNameFilters(QStringList() <<QLatin1String("*.qpf2"));

   dir.refresh();

   for (int i = 0; i < int(dir.count()); ++i) {

       const QByteArray fileName =QFile::encodeName(dir.absoluteFilePath(dir[i]));

       QFile file(QString::fromLocal8Bit(fileName));

       if (file.open(QFile::ReadOnly)) {

           const QByteArray fileData = file.readAll();

           QByteArray *fileDataPtr = new QByteArray(fileData);

           registerQPF2Font(fileData, fileDataPtr);

       }

    }

}

從兩個類的方法中可以看到QBasicFontDatabase::populateFontDatabase()中是在對ttf等字型進行載入。而QPlatformFontDatabase::populateFontDatabase()中是對qpf2字型進行載入。所以這就解釋了為什麼Qt5.6.1不能使用qpf2字型。這個載入qpf2字型的方法沒有被呼叫啊。肯定怎麼也支援不了qpf2。所以果斷的將QBasicFontDatabase這個類相關的檔案註釋掉(這樣程式在執行的時候就自動呼叫了父類也就是QPlatformFontDatabase::populateFontDatabase()方法,這個方法是個虛擬函式)。這裡包括qbasicfontdatabase_p.h中QBasicFontDatabase類的定義和qbasicfontdatabase.cpp整個檔案的內容(#if 0 .......#endif即可)。

重新編譯Qt原始碼,將qpf2檔案放在字型目錄下(lib/fonts/dejavu_sans_11_50.qpf2)。開機執行生程式可顯示字元不dump掉了。剩下的工作就是製作字型了。