Implement API for enabling / disabling OpenType features
Similar to the font-features-settings in CSS, this is a low-level API that allows you to pass the information to the shaper in order to enable or disable specific font features by name. [ChangeLog][QtGui][Text] Added an API to QFont which makes it possible to enable and disable specific typographic features in OpenType fonts. Change-Id: Ib48c678f3b97a5a562b08ae34dc895800c8885c0 Reviewed-by: Lars Knoll <lars@knoll.priv.no>
This commit is contained in:
parent
b1d59d6dd9
commit
6160ea45b6
@ -213,7 +213,7 @@ QFontPrivate::QFontPrivate(const QFontPrivate &other)
|
||||
strikeOut(other.strikeOut), kerning(other.kerning),
|
||||
capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
|
||||
letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
|
||||
scFont(other.scFont)
|
||||
fontFeatures(other.fontFeatures), scFont(other.scFont)
|
||||
{
|
||||
if (scFont && scFont != this)
|
||||
scFont->ref.ref();
|
||||
@ -343,9 +343,20 @@ void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
|
||||
wordSpacing = other->wordSpacing;
|
||||
if (! (mask & QFont::CapitalizationResolved))
|
||||
capital = other->capital;
|
||||
|
||||
if (!(mask & QFont::FontFeaturesResolved))
|
||||
fontFeatures = other->fontFeatures;
|
||||
}
|
||||
|
||||
void QFontPrivate::setFontFeature(quint32 tag, quint32 value)
|
||||
{
|
||||
fontFeatures.insert(tag, value);
|
||||
}
|
||||
|
||||
void QFontPrivate::unsetFontFeature(quint32 tag)
|
||||
{
|
||||
fontFeatures.remove(tag);
|
||||
}
|
||||
|
||||
|
||||
QFontEngineData::QFontEngineData()
|
||||
@ -1748,6 +1759,7 @@ bool QFont::operator==(const QFont &f) const
|
||||
&& f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
|
||||
&& f.d->letterSpacing == d->letterSpacing
|
||||
&& f.d->wordSpacing == d->wordSpacing
|
||||
&& f.d->fontFeatures == d->fontFeatures
|
||||
));
|
||||
}
|
||||
|
||||
@ -1785,7 +1797,21 @@ bool QFont::operator<(const QFont &f) const
|
||||
|
||||
int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
|
||||
int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
|
||||
return f1attrs < f2attrs;
|
||||
if (f1attrs != f2attrs) return f1attrs < f2attrs;
|
||||
|
||||
if (d->fontFeatures.size() != f.d->fontFeatures.size())
|
||||
return f.d->fontFeatures.size() < d->fontFeatures.size();
|
||||
|
||||
auto it = d->fontFeatures.constBegin();
|
||||
auto jt = f.d->fontFeatures.constBegin();
|
||||
for (; it != d->fontFeatures.constEnd(); ++it, ++jt) {
|
||||
if (it.key() != jt.key())
|
||||
return jt.key() < it.key();
|
||||
if (it.value() != jt.value())
|
||||
return jt.value() < it.value();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -2206,6 +2232,179 @@ void QFont::cacheStatistics()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
|
||||
Applies integer values to specific OpenType features when shaping the text based on the contents
|
||||
in \a fontFeatures. This provides advanced access to the font shaping process, and can be used
|
||||
to support font features that are otherwise not covered in the API.
|
||||
|
||||
An OpenType feature is defined by a 32-bit tag (encoded from the four-character name of the
|
||||
table by using the stringToTag() function), as well as an integer value.
|
||||
|
||||
This integer value passed along with the tag in most cases represents a boolean value: A zero
|
||||
value means the feature is disabled, and a non-zero value means it is enabled. For certain
|
||||
font features, however, it may have other intepretations. For example, when applied to the
|
||||
\c salt feature, the value is an index that specifies the stylistic alternative to use.
|
||||
|
||||
For example, the \c frac font feature will convert diagonal fractions separated with a slash
|
||||
(such as \c 1/2) with a different representation. Typically this will involve baking the full
|
||||
fraction into a single character width (such as \c ½).
|
||||
|
||||
If a font supports the \c frac feature, then it can be enabled in the shaper by setting
|
||||
\c{fontFeatures[stringToTag("frac")] = 1} in the font feature map.
|
||||
|
||||
This function will overwrite the current list of explicit font features. Use setFontFeature() or
|
||||
unsetFontFeature() to set or unset individual features.
|
||||
|
||||
\note By default, Qt will enable and disable certain font features based on other font
|
||||
properties. In particular, the \c kern feature will be enabled/disabled depending on the
|
||||
\l kerning() property of the QFont. In addition, all ligature features
|
||||
(\c liga, \c clig, \c dlig, \c hlig) will be disabled if a \l letterSpacing() is applied,
|
||||
but only for writing systems where the use of ligature is cosmetic. For writing systems where
|
||||
ligatures are required, the features will remain in their default state. The values set using
|
||||
setFontFeatures() and related functions will override the default behavior. If, for instance,
|
||||
the \c{fontFeatures[stringToTag("kern")]} is set to 1, then kerning will always be enabled,
|
||||
regardless of whether the kerning property is set to false. Similarly, if it is set to 0, then
|
||||
it will always be disabled. To reset a font feature to its default behavior, you can unset it
|
||||
in the fontFeatures hash, for example by using unsetFontFeature().
|
||||
|
||||
\sa setFontFeature(), unsetFontFeature(), fontFeatures()
|
||||
*/
|
||||
void QFont::setFontFeatures(const QHash<quint32, quint32> &fontFeatures)
|
||||
{
|
||||
d->detachButKeepEngineData(this);
|
||||
d->fontFeatures = fontFeatures;
|
||||
resolve_mask |= QFont::FontFeaturesResolved;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
\overload
|
||||
|
||||
Sets the \a value for a specific font feature \a tag. This is an advanced feature which can be
|
||||
used to enable or disable specific OpenType features if they are available in the font. See
|
||||
\l setFontFeatures() for more details.
|
||||
|
||||
\sa setFontFeatures(), unsetFontFeature(), fontFeatures()
|
||||
*/
|
||||
void QFont::setFontFeature(quint32 tag, quint32 value)
|
||||
{
|
||||
d->detachButKeepEngineData(this);
|
||||
d->setFontFeature(tag, value);
|
||||
resolve_mask |= QFont::FontFeaturesResolved;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
\overload
|
||||
|
||||
Sets the \a value of a specific \a fontFeature. This is an advanced feature which can be used to
|
||||
enable or disable specific OpenType features if they are available in the font. See
|
||||
\l setFontFeatures() for more details.
|
||||
|
||||
\note This is equivalent to calling setFontFeature(stringToTag(fontFeature), value).
|
||||
|
||||
\sa setFontFeatures(), unsetFontFeature(), fontFeatures()
|
||||
*/
|
||||
void QFont::setFontFeature(const char *fontFeature, quint32 value)
|
||||
{
|
||||
setFontFeature(stringToTag(fontFeature), value);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
\overload
|
||||
|
||||
Unsets the \a fontFeature from the map of explicitly enabled/disabled features.
|
||||
|
||||
\note Even if the feature has not previously been added, this will mark the font features map
|
||||
as modified in this QFont, so that it will take precedence when resolving against other fonts.
|
||||
|
||||
Unsetting an existing feature on the QFont reverts behavior to the default. See
|
||||
\l setFontFeatures() for more details.
|
||||
|
||||
\sa setFontFeatures(), setFontFeature(), fontFeatures()
|
||||
*/
|
||||
void QFont::unsetFontFeature(quint32 tag)
|
||||
{
|
||||
d->detachButKeepEngineData(this);
|
||||
d->unsetFontFeature(tag);
|
||||
resolve_mask |= QFont::FontFeaturesResolved;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
\overload
|
||||
|
||||
Unsets the \a fontFeature from the map of explicitly enabled/disabled features.
|
||||
|
||||
\note Even if the feature has not previously been added, this will mark the font features map
|
||||
as modified in this QFont, so that it will take precedence when resolving against other fonts.
|
||||
|
||||
Unsetting an existing feature on the QFont reverts behavior to the default. See
|
||||
\l setFontFeatures() for more details.
|
||||
|
||||
\note This is equivalent to calling unsetFontFeature(stringToTag(fontFeature)).
|
||||
|
||||
\sa setFontFeatures(), setFontFeature(), fontFeatures()
|
||||
*/
|
||||
void QFont::unsetFontFeature(const char *fontFeature)
|
||||
{
|
||||
unsetFontFeature(stringToTag(fontFeature));
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
|
||||
Returns the hash of explicitly set font features in the QFont. By default this map is empty and
|
||||
the shaping process will use default features based on other font or text properties.
|
||||
|
||||
Unsetting an existing feature on the QFont reverts behavior to the default. See
|
||||
\l setFontFeatures() for more details.
|
||||
|
||||
The key of the returned QHash refers to the font table tag as it's encoded in the font
|
||||
file. It can be converted to a QByteArray using the tagToString() function.
|
||||
|
||||
\sa setFontFeatures(), setFontFeature(), unsetFontFeature()
|
||||
*/
|
||||
QHash<quint32, quint32> QFont::fontFeatures() const
|
||||
{
|
||||
return d->fontFeatures;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
|
||||
Returns the decoded name for \a tag.
|
||||
|
||||
\sa setFontFeatures(), setFontFeature(), unsetFontFeature(), stringToTag()
|
||||
*/
|
||||
QByteArray QFont::tagToString(quint32 tag)
|
||||
{
|
||||
char str[4] =
|
||||
{ char((tag & 0xff000000) >> 24),
|
||||
char((tag & 0x00ff0000) >> 16),
|
||||
char((tag & 0x0000ff00) >> 8),
|
||||
char((tag & 0x000000ff)) };
|
||||
return QByteArray(str, 4);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
|
||||
Returns the encoded tag for \a name. The \a name must be a null-terminated string of exactly
|
||||
four characters. Returns 0 on error.
|
||||
|
||||
\sa setFontFeatures(), setFontFeature(), unsetFontFeature(), tagToString()
|
||||
*/
|
||||
quint32 QFont::stringToTag(const char *name)
|
||||
{
|
||||
if (qstrlen(name) != 4)
|
||||
return 0;
|
||||
|
||||
return MAKE_TAG(name[0], name[1], name[2], name[3]);
|
||||
}
|
||||
|
||||
extern QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style,
|
||||
QFont::StyleHint styleHint, QChar::Script script);
|
||||
@ -2343,6 +2542,8 @@ QDataStream &operator<<(QDataStream &s, const QFont &font)
|
||||
else
|
||||
s << font.d->request.families;
|
||||
}
|
||||
if (s.version() >= QDataStream::Qt_6_6)
|
||||
s << font.d->fontFeatures;
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -2457,6 +2658,11 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
|
||||
else
|
||||
font.d->request.families = value;
|
||||
}
|
||||
if (s.version() >= QDataStream::Qt_6_6) {
|
||||
font.d->fontFeatures.clear();
|
||||
s >> font.d->fontFeatures;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,8 @@ public:
|
||||
HintingPreferenceResolved = 0x8000,
|
||||
StyleNameResolved = 0x10000,
|
||||
FamiliesResolved = 0x20000,
|
||||
AllPropertiesResolved = 0x3ffff
|
||||
FontFeaturesResolved = 0x40000,
|
||||
AllPropertiesResolved = 0x7ffff
|
||||
};
|
||||
Q_ENUM(ResolveProperties)
|
||||
|
||||
@ -206,6 +207,16 @@ public:
|
||||
void setHintingPreference(HintingPreference hintingPreference);
|
||||
HintingPreference hintingPreference() const;
|
||||
|
||||
void setFontFeature(const char *fontFeature, quint32 value);
|
||||
void setFontFeature(quint32 tag, quint32 value);
|
||||
void setFontFeatures(const QHash<quint32, quint32> &fontFeatures);
|
||||
void unsetFontFeature(quint32 tag);
|
||||
void unsetFontFeature(const char *tag);
|
||||
QHash<quint32, quint32> fontFeatures() const;
|
||||
|
||||
static QByteArray tagToString(quint32 tag);
|
||||
static quint32 stringToTag(const char *tagString);
|
||||
|
||||
// dupicated from QFontInfo
|
||||
bool exactMatch() const;
|
||||
|
||||
|
@ -164,6 +164,7 @@ public:
|
||||
|
||||
QFixed letterSpacing;
|
||||
QFixed wordSpacing;
|
||||
QHash<quint32, quint32> fontFeatures;
|
||||
|
||||
mutable QFontPrivate *scFont;
|
||||
QFont smallCapsFont() const { return QFont(smallCapsFontPrivate()); }
|
||||
@ -178,6 +179,9 @@ public:
|
||||
|
||||
static void detachButKeepEngineData(QFont *font);
|
||||
|
||||
void setFontFeature(quint32 tag, quint32 value);
|
||||
void unsetFontFeature(quint32 tag);
|
||||
|
||||
private:
|
||||
QFontPrivate &operator=(const QFontPrivate &) { return *this; }
|
||||
};
|
||||
|
@ -1404,6 +1404,7 @@ void QTextEngine::shapeText(int item) const
|
||||
bool kerningEnabled;
|
||||
bool letterSpacingIsAbsolute;
|
||||
bool shapingEnabled = false;
|
||||
QHash<quint32, quint32> fontFeatures;
|
||||
QFixed letterSpacing, wordSpacing;
|
||||
#ifndef QT_NO_RAWFONT
|
||||
if (useRawFont) {
|
||||
@ -1417,6 +1418,7 @@ void QTextEngine::shapeText(int item) const
|
||||
wordSpacing = QFixed::fromReal(font.wordSpacing());
|
||||
letterSpacing = QFixed::fromReal(font.letterSpacing());
|
||||
letterSpacingIsAbsolute = true;
|
||||
fontFeatures = font.d->fontFeatures;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@ -1429,6 +1431,7 @@ void QTextEngine::shapeText(int item) const
|
||||
letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute;
|
||||
letterSpacing = font.d->letterSpacing;
|
||||
wordSpacing = font.d->wordSpacing;
|
||||
fontFeatures = font.d->fontFeatures;
|
||||
|
||||
if (letterSpacingIsAbsolute && letterSpacing.value())
|
||||
letterSpacing *= font.d->dpi / qt_defaultDpiY();
|
||||
@ -1482,7 +1485,14 @@ void QTextEngine::shapeText(int item) const
|
||||
|
||||
#if QT_CONFIG(harfbuzz)
|
||||
if (Q_LIKELY(shapingEnabled)) {
|
||||
si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);
|
||||
si.num_glyphs = shapeTextWithHarfbuzzNG(si,
|
||||
string,
|
||||
itemLength,
|
||||
fontEngine,
|
||||
itemBoundaries,
|
||||
kerningEnabled,
|
||||
letterSpacing != 0,
|
||||
fontFeatures);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@ -1594,7 +1604,8 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
|
||||
QFontEngine *fontEngine,
|
||||
const QList<uint> &itemBoundaries,
|
||||
bool kerningEnabled,
|
||||
bool hasLetterSpacing) const
|
||||
bool hasLetterSpacing,
|
||||
const QHash<quint32, quint32> &fontFeatures) const
|
||||
{
|
||||
uint glyphs_shaped = 0;
|
||||
|
||||
@ -1648,14 +1659,24 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
|
||||
|| script == QChar::Script_Khmer || script == QChar::Script_Nko);
|
||||
|
||||
bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;
|
||||
const hb_feature_t features[5] = {
|
||||
{ HB_TAG('k','e','r','n'), !!kerningEnabled, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
|
||||
{ HB_TAG('l','i','g','a'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
|
||||
{ HB_TAG('c','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
|
||||
{ HB_TAG('d','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
|
||||
{ HB_TAG('h','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END }
|
||||
};
|
||||
const int num_features = dontLigate ? 5 : 1;
|
||||
|
||||
QHash<quint32, quint32> features;
|
||||
features.insert(HB_TAG('k','e','r','n'), !!kerningEnabled);
|
||||
if (dontLigate) {
|
||||
features.insert(HB_TAG('l','i','g','a'), false);
|
||||
features.insert(HB_TAG('c','l','i','g'), false);
|
||||
features.insert(HB_TAG('d','l','i','g'), false);
|
||||
features.insert(HB_TAG('h','l','i','g'), false);
|
||||
}
|
||||
features.insert(fontFeatures);
|
||||
|
||||
QVarLengthArray<hb_feature_t, 16> featureArray;
|
||||
for (auto it = features.constBegin(); it != features.constEnd(); ++it) {
|
||||
featureArray.append({ it.key(),
|
||||
it.value(),
|
||||
HB_FEATURE_GLOBAL_START,
|
||||
HB_FEATURE_GLOBAL_END });
|
||||
}
|
||||
|
||||
// whitelist cross-platforms shapers only
|
||||
static const char *shaper_list[] = {
|
||||
@ -1665,7 +1686,11 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
|
||||
nullptr
|
||||
};
|
||||
|
||||
bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, shaper_list);
|
||||
bool shapedOk = hb_shape_full(hb_font,
|
||||
buffer,
|
||||
featureArray.constData(),
|
||||
features.size(),
|
||||
shaper_list);
|
||||
if (Q_UNLIKELY(!shapedOk)) {
|
||||
hb_buffer_destroy(buffer);
|
||||
return 0;
|
||||
|
@ -621,9 +621,14 @@ private:
|
||||
void addRequiredBoundaries() const;
|
||||
void shapeText(int item) const;
|
||||
#if QT_CONFIG(harfbuzz)
|
||||
int shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *string, int itemLength,
|
||||
QFontEngine *fontEngine, const QList<uint> &itemBoundaries,
|
||||
bool kerningEnabled, bool hasLetterSpacing) const;
|
||||
int shapeTextWithHarfbuzzNG(const QScriptItem &si,
|
||||
const ushort *string,
|
||||
int itemLength,
|
||||
QFontEngine *fontEngine,
|
||||
const QList<uint> &itemBoundaries,
|
||||
bool kerningEnabled,
|
||||
bool hasLetterSpacing,
|
||||
const QHash<quint32, quint32> &fontFeatures) const;
|
||||
#endif
|
||||
|
||||
int endOfLine(int lineNum);
|
||||
|
17
tests/manual/fontfeatures/fontfeatures.pro
Normal file
17
tests/manual/fontfeatures/fontfeatures.pro
Normal file
@ -0,0 +1,17 @@
|
||||
TEMPLATE = app
|
||||
TARGET = fontfeatures
|
||||
INCLUDEPATH += .
|
||||
QT += widgets
|
||||
|
||||
# You can make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# Please consult the documentation of the deprecated API in order to know
|
||||
# how to port your code away from it.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_UP_TO=0x060000 # disables all APIs deprecated in Qt 6.0.0 and earlier
|
||||
|
||||
# Input
|
||||
HEADERS += mainwindow.h
|
||||
FORMS += mainwindow.ui
|
||||
SOURCES += main.cpp \
|
||||
mainwindow.cpp \
|
14
tests/manual/fontfeatures/main.cpp
Normal file
14
tests/manual/fontfeatures/main.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
225
tests/manual/fontfeatures/mainwindow.cpp
Normal file
225
tests/manual/fontfeatures/mainwindow.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setup();
|
||||
updateSampleText();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::updateSampleText()
|
||||
{
|
||||
QFont font = ui->fontComboBox->currentFont();
|
||||
font.setPixelSize(54);
|
||||
|
||||
for (int i = 0; i < ui->lwFeatures->count(); ++i) {
|
||||
QListWidgetItem *it = ui->lwFeatures->item(i);
|
||||
if (it->checkState() != Qt::PartiallyChecked) {
|
||||
QByteArray ba = it->text().toLatin1();
|
||||
font.setFontFeature(ba, !!it->checkState());
|
||||
}
|
||||
}
|
||||
|
||||
ui->lSampleDisplay->setFont(font);
|
||||
ui->lSampleDisplay->setText(ui->leSampleText->text());
|
||||
}
|
||||
|
||||
void MainWindow::enableAll()
|
||||
{
|
||||
for (int i = 0; i < ui->lwFeatures->count(); ++i) {
|
||||
QListWidgetItem *it = ui->lwFeatures->item(i);
|
||||
it->setCheckState(Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::disableAll()
|
||||
{
|
||||
for (int i = 0; i < ui->lwFeatures->count(); ++i) {
|
||||
QListWidgetItem *it = ui->lwFeatures->item(i);
|
||||
it->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::reset()
|
||||
{
|
||||
for (int i = 0; i < ui->lwFeatures->count(); ++i) {
|
||||
QListWidgetItem *it = ui->lwFeatures->item(i);
|
||||
it->setCheckState(Qt::PartiallyChecked);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setup()
|
||||
{
|
||||
connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, &MainWindow::updateSampleText);
|
||||
connect(ui->leSampleText, &QLineEdit::textChanged, this, &MainWindow::updateSampleText);
|
||||
connect(ui->lwFeatures, &QListWidget::itemChanged, this, &MainWindow::updateSampleText);
|
||||
connect(ui->pbEnableAll, &QPushButton::clicked, this, &MainWindow::enableAll);
|
||||
connect(ui->pbDisableAll, &QPushButton::clicked, this, &MainWindow::disableAll);
|
||||
connect(ui->pbReset, &QPushButton::clicked, this, &MainWindow::reset);
|
||||
|
||||
QList<QByteArray> featureList =
|
||||
{
|
||||
"aalt",
|
||||
"abvf",
|
||||
"abvm",
|
||||
"abvs",
|
||||
"afrc",
|
||||
"akhn",
|
||||
"blwf",
|
||||
"blwm",
|
||||
"blws",
|
||||
"calt",
|
||||
"case",
|
||||
"ccmp",
|
||||
"cfar",
|
||||
"chws",
|
||||
"cjct",
|
||||
"clig",
|
||||
"cpct",
|
||||
"cpsp",
|
||||
"cswh",
|
||||
"curs",
|
||||
"cv01",
|
||||
"c2pc",
|
||||
"c2sc",
|
||||
"dist",
|
||||
"dlig",
|
||||
"dnom",
|
||||
"dtls",
|
||||
"expt",
|
||||
"falt",
|
||||
"fin2",
|
||||
"fin3",
|
||||
"fina",
|
||||
"flac",
|
||||
"frac",
|
||||
"fwid",
|
||||
"half",
|
||||
"haln",
|
||||
"halt",
|
||||
"hist",
|
||||
"hkna",
|
||||
"hlig",
|
||||
"hngl",
|
||||
"hojo",
|
||||
"hwid",
|
||||
"init",
|
||||
"isol",
|
||||
"ital",
|
||||
"jalt",
|
||||
"jp78",
|
||||
"jp83",
|
||||
"jp90",
|
||||
"jp04",
|
||||
"kern",
|
||||
"lfbd",
|
||||
"liga",
|
||||
"ljmo",
|
||||
"lnum",
|
||||
"locl",
|
||||
"ltra",
|
||||
"ltrm",
|
||||
"mark",
|
||||
"med2",
|
||||
"medi",
|
||||
"mgrk",
|
||||
"mkmk",
|
||||
"mset",
|
||||
"nalt",
|
||||
"nlck",
|
||||
"nukt",
|
||||
"numr",
|
||||
"onum",
|
||||
"opbd",
|
||||
"ordn",
|
||||
"ornm",
|
||||
"palt",
|
||||
"pcap",
|
||||
"pkna",
|
||||
"pnum",
|
||||
"pref",
|
||||
"pres",
|
||||
"pstf",
|
||||
"psts",
|
||||
"pwid",
|
||||
"qwid",
|
||||
"rand",
|
||||
"rclt",
|
||||
"rkrf",
|
||||
"rlig",
|
||||
"rphf",
|
||||
"rtbd",
|
||||
"rtla",
|
||||
"rtlm",
|
||||
"ruby",
|
||||
"rvrn",
|
||||
"salt",
|
||||
"sinf",
|
||||
"size",
|
||||
"smcp",
|
||||
"smpl",
|
||||
"ss01",
|
||||
"ss02",
|
||||
"ss03",
|
||||
"ss04",
|
||||
"ss05",
|
||||
"ss06",
|
||||
"ss07",
|
||||
"ss08",
|
||||
"ss09",
|
||||
"ss10",
|
||||
"ss11",
|
||||
"ss12",
|
||||
"ss13",
|
||||
"ss14",
|
||||
"ss15",
|
||||
"ss16",
|
||||
"ss17",
|
||||
"ss18",
|
||||
"ss19",
|
||||
"ss20",
|
||||
"ssty",
|
||||
"stch",
|
||||
"subs",
|
||||
"sups",
|
||||
"swsh",
|
||||
"titl",
|
||||
"tjmo",
|
||||
"tnam",
|
||||
"tnum",
|
||||
"trad",
|
||||
"twid",
|
||||
"unic",
|
||||
"valt",
|
||||
"vatu",
|
||||
"vchw",
|
||||
"vert",
|
||||
"vhal",
|
||||
"vjmo",
|
||||
"vkna",
|
||||
"vkrn",
|
||||
"vpal",
|
||||
"vrt2",
|
||||
"vrtr",
|
||||
"zero"
|
||||
};
|
||||
|
||||
for (auto it = featureList.constBegin(); it != featureList.constEnd(); ++it) {
|
||||
QListWidgetItem *item = new QListWidgetItem(*it);
|
||||
item->setFlags(Qt::ItemIsUserTristate | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
||||
item->setCheckState(Qt::PartiallyChecked);
|
||||
ui->lwFeatures->addItem(item);
|
||||
}
|
||||
}
|
32
tests/manual/fontfeatures/mainwindow.h
Normal file
32
tests/manual/fontfeatures/mainwindow.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void updateSampleText();
|
||||
void enableAll();
|
||||
void disableAll();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
void setup();
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
116
tests/manual/fontfeatures/mainwindow.ui
Normal file
116
tests/manual/fontfeatures/mainwindow.ui
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFontComboBox" name="fontComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Sample text:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="leSampleText">
|
||||
<property name="text">
|
||||
<string>Foobar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbEnableAll">
|
||||
<property name="text">
|
||||
<string>Enable all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbDisableAll">
|
||||
<property name="text">
|
||||
<string>Disable all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwFeatures">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::TopToBottom</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::ListMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lSampleDisplay">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LABEL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -5,6 +5,7 @@ SUBDIRS = \
|
||||
filetest \
|
||||
embeddedintoforeignwindow \
|
||||
foreignwindows \
|
||||
fontfeatures \
|
||||
gestures \
|
||||
highdpi \
|
||||
inputmethodhints \
|
||||
|
Loading…
x
Reference in New Issue
Block a user