From a38f8d96fc5781e6d99eadbd435f408f8729ac1b Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 10 Jul 2014 17:16:09 +0200 Subject: [PATCH] Add QQuickFontMetrics. This will be a private C++ type that is exposed to QtQuick 2.4 as FontMetrics. [ChangeLog][QtQuick] Added QQuickFontMetrics, which provides a subset of QFontMetricsF's API. Change-Id: Iac31e5a555bd8f1dc0904b8de0408e5f1a402b25 Reviewed-by: J-P Nurmi Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/util/qquickfontmetrics.cpp | 334 +++++++++++++++++++++ src/quick/util/qquickfontmetrics_p.h | 114 +++++++ src/quick/util/qquickutilmodule.cpp | 3 + src/quick/util/util.pri | 6 +- .../quick/qquickfontmetrics/qquickfontmetrics.pro | 10 + .../qquickfontmetrics/tst_quickfontmetrics.cpp | 150 +++++++++ tests/auto/quick/quick.pro | 1 + 7 files changed, 616 insertions(+), 2 deletions(-) create mode 100644 src/quick/util/qquickfontmetrics.cpp create mode 100644 src/quick/util/qquickfontmetrics_p.h create mode 100644 tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro create mode 100644 tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp diff --git a/src/quick/util/qquickfontmetrics.cpp b/src/quick/util/qquickfontmetrics.cpp new file mode 100644 index 0000000..bf53399 --- /dev/null +++ b/src/quick/util/qquickfontmetrics.cpp @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickfontmetrics_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype FontMetrics + \instantiates QQuickFontMetrics + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Provides metrics for a given font + + FontMetrics calculates the size of characters and strings for a given font. + + It provides a subset of the C++ \l QFontMetricsF API, with the added + ability to change the font that is used for calculations via the \l font + property. + + \code + FontMetrics { + id: fontMetrics + font.family: "Arial" + } + + Rectangle { + width: fontMetrics.height() * 4 + height: fontMetrics.height() * 2 + } + \endcode + + \sa QFontMetricsF +*/ +QQuickFontMetrics::QQuickFontMetrics(QObject *parent) : + QObject(parent), + m_metrics(m_font) +{ +} + +QQuickFontMetrics::~QQuickFontMetrics() +{ +} + +/*! + \qmlproperty font QtQuick::FontMetrics::font + + This property holds the font used for the metrics calculations. +*/ +QFont QQuickFontMetrics::font() const +{ + return m_font; +} + +void QQuickFontMetrics::setFont(const QFont &font) +{ + if (m_font != font) { + m_font = font; + m_metrics = QFontMetricsF(m_font); + emit fontChanged(m_font); + } +} + +/*! + \qmlproperty real QtQuick::FontMetrics::ascent + + This property holds the ascent of the font. + + \sa {QFontMetricsF::ascent()}, descent, height +*/ +qreal QQuickFontMetrics::ascent() const +{ + return m_metrics.ascent(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::descent + + This property holds the descent of the font. + + \sa {QFontMetricsF::descent()}, ascent, height +*/ +qreal QQuickFontMetrics::descent() const +{ + return m_metrics.descent(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::height + + This property holds the height of the font. + + \sa {QFontMetricsF::height()} +*/ +qreal QQuickFontMetrics::height() const +{ + return m_metrics.height(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::leading + + This property holds the leading of the font. + + \sa {QFontMetricsF::leading()} +*/ +qreal QQuickFontMetrics::leading() const +{ + return m_metrics.leading(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::lineSpacing + + This property holds the distance from one base line to the next. + + \sa {QFontMetricsF::lineSpacing()} +*/ +qreal QQuickFontMetrics::lineSpacing() const +{ + return m_metrics.lineSpacing(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::minimumLeftBearing + + This property holds the minimum left bearing of the font. + + \sa {QFontMetricsF::minLeftBearing()} +*/ +qreal QQuickFontMetrics::minimumLeftBearing() const +{ + return m_metrics.minLeftBearing(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::minimumRightBearing + + This property holds the minimum right bearing of the font. + + \sa {QFontMetricsF::minRightBearing()} +*/ +qreal QQuickFontMetrics::minimumRightBearing() const +{ + return m_metrics.minRightBearing(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::maximumCharacterWidth + + This property holds the width of the widest character in the font. + + \sa {QFontMetricsF::maxWidth()} +*/ +qreal QQuickFontMetrics::maximumCharacterWidth() const +{ + return m_metrics.maxWidth(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::xHeight + + This property holds the 'x' height of the font. + + \sa {QFontMetricsF::xHeight()} +*/ +qreal QQuickFontMetrics::xHeight() const +{ + return m_metrics.xHeight(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::averageCharacterWidth + + This property holds the average width of glyphs in the font. + + \sa {QFontMetricsF::averageCharWidth()} +*/ +qreal QQuickFontMetrics::averageCharacterWidth() const +{ + return m_metrics.averageCharWidth(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::underlinePosition + + This property holds the distance from the base line to where an underscore + should be drawn. + + \sa {QFontMetricsF::underlinePos()}, overlinePosition, strikeOutPosition +*/ +qreal QQuickFontMetrics::underlinePosition() const +{ + return m_metrics.underlinePos(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::overlinePosition + + This property holds the distance from the base line to where an overline + should be drawn. + + \sa {QFontMetricsF::overlinePos()}, underlinePosition, strikeOutPosition +*/ +qreal QQuickFontMetrics::overlinePosition() const +{ + return m_metrics.overlinePos(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::strikeOutPosition + + This property holds the distance from the base line to where the strikeout + line should be drawn. + + \sa {QFontMetricsF::strikeOutPos()}, overlinePosition, underlinePosition +*/ +qreal QQuickFontMetrics::strikeOutPosition() const +{ + return m_metrics.strikeOutPos(); +} + +/*! + \qmlproperty real QtQuick::FontMetrics::lineWidth + + This property holds the width of the underline and strikeout lines, + adjusted for the point size of the font. + + \sa {QFontMetricsF::lineWidth()} +*/ +qreal QQuickFontMetrics::lineWidth() const +{ + return m_metrics.lineWidth(); +} + +/*! + \qmlmethod qreal QtQuick::FontMetrics::advanceWidth(string text) + + This method returns the advance in pixels of the characters in \a text. + This is the distance from the position of the string to where the next + string should be drawn. + + \sa {QFontMetricsF::width()}, height() +*/ +qreal QQuickFontMetrics::advanceWidth(const QString &text) const +{ + return m_metrics.width(text); +} + +/*! + \qmlmethod rect QtQuick::FontMetrics::boundingRect(string text) + + This method returns the bounding rectangle of the characters in the string + specified by \a text. + + \sa {QFontMetricsF::boundingRect()}, tightBoundingRect() +*/ +QRectF QQuickFontMetrics::boundingRect(const QString &text) const +{ + return m_metrics.boundingRect(text); +} + +/*! + \qmlmethod rect QtQuick::FontMetrics::tightBoundingRect(string text) + + This method returns a tight bounding rectangle around the characters in the + string specified by \a text. + + \sa {QFontMetricsF::tightBoundingRect()}, boundingRect() +*/ +QRectF QQuickFontMetrics::tightBoundingRect(const QString &text) const +{ + return m_metrics.tightBoundingRect(text); +} + +/*! + \qmlmethod string QtQuick::FontMetrics::elidedText(string text, enum mode, + qreal width, int flags) + + This method returns a returns an elided version of the string (i.e., a + string with "..." in it) if the string \a text is wider than \a width. + Otherwise, returns the original string. + + The \a flags argument is optional and currently only supports + \l {Qt::TextShowMnemonic}. + + \sa {QFontMetricsF::elidedText()} +*/ +QString QQuickFontMetrics::elidedText(const QString &text, Qt::TextElideMode mode, qreal width, int flags) const +{ + return m_metrics.elidedText(text, mode, width, flags); +} + +QT_END_NAMESPACE diff --git a/src/quick/util/qquickfontmetrics_p.h b/src/quick/util/qquickfontmetrics_p.h new file mode 100644 index 0000000..4017fd4 --- /dev/null +++ b/src/quick/util/qquickfontmetrics_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKFONTMETRICS_H +#define QQUICKFONTMETRICS_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QFont; + +class Q_AUTOTEST_EXPORT QQuickFontMetrics : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) + Q_PROPERTY(qreal ascent READ ascent NOTIFY fontChanged) + Q_PROPERTY(qreal descent READ descent NOTIFY fontChanged) + Q_PROPERTY(qreal height READ height NOTIFY fontChanged) + Q_PROPERTY(qreal leading READ leading NOTIFY fontChanged) + Q_PROPERTY(qreal lineSpacing READ lineSpacing NOTIFY fontChanged) + Q_PROPERTY(qreal minimumLeftBearing READ minimumLeftBearing NOTIFY fontChanged) + Q_PROPERTY(qreal minimumRightBearing READ minimumRightBearing NOTIFY fontChanged) + Q_PROPERTY(qreal maximumCharacterWidth READ maximumCharacterWidth NOTIFY fontChanged) + Q_PROPERTY(qreal xHeight READ xHeight NOTIFY fontChanged) + Q_PROPERTY(qreal averageCharacterWidth READ averageCharacterWidth NOTIFY fontChanged) + Q_PROPERTY(qreal underlinePosition READ underlinePosition NOTIFY fontChanged) + Q_PROPERTY(qreal overlinePosition READ overlinePosition NOTIFY fontChanged) + Q_PROPERTY(qreal strikeOutPosition READ strikeOutPosition NOTIFY fontChanged) + Q_PROPERTY(qreal lineWidth READ lineWidth NOTIFY fontChanged) +public: + explicit QQuickFontMetrics(QObject *parent = 0); + ~QQuickFontMetrics(); + + QFont font() const; + void setFont(const QFont &font); + + qreal ascent() const; + qreal descent() const; + qreal height() const; + qreal leading() const; + qreal lineSpacing() const; + qreal minimumLeftBearing() const; + qreal minimumRightBearing() const; + qreal maximumCharacterWidth() const; + + qreal xHeight() const; + qreal averageCharacterWidth() const; + + qreal underlinePosition() const; + qreal overlinePosition() const; + qreal strikeOutPosition() const; + qreal lineWidth() const; + + Q_INVOKABLE qreal advanceWidth(const QString &text) const; + Q_INVOKABLE QRectF boundingRect(const QString &text) const; + Q_INVOKABLE QRectF tightBoundingRect(const QString &text) const; + Q_INVOKABLE QString elidedText(const QString &text, Qt::TextElideMode mode, qreal width, int flags = 0) const; + +Q_SIGNALS: + void fontChanged(const QFont &font); + +private: + QFont m_font; + QFontMetricsF m_metrics; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickFontMetrics) + +#endif // QQUICKFONTMETRICS_H diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index a6e9077..1d82cfc 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -45,6 +45,7 @@ #include "qquickbehavior_p.h" #include "qquicksmoothedanimation_p.h" #include "qquickfontloader_p.h" +#include "qquickfontmetrics_p.h" #include "qquickpropertychanges_p.h" #include "qquickspringanimation_p.h" #include "qquickstategroup_p.h" @@ -106,4 +107,6 @@ void QQuickUtilModule::defineModule() qRegisterMetaType(); qmlRegisterUncreatableType("QtQuick", 2, 2, "StandardKey", QStringLiteral("Cannot create an instance of StandardKey.")); + + qmlRegisterType("QtQuick", 2, 4, "FontMetrics"); } diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index ce409bd..3555307 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -26,7 +26,8 @@ SOURCES += \ $$PWD/qquickanimator.cpp \ $$PWD/qquickanimatorjob.cpp \ $$PWD/qquickanimatorcontroller.cpp \ - $$PWD/qquickprofiler.cpp + $$PWD/qquickprofiler.cpp \ + $$PWD/qquickfontmetrics.cpp HEADERS += \ $$PWD/qquickapplication_p.h\ @@ -60,4 +61,5 @@ HEADERS += \ $$PWD/qquickanimator_p_p.h \ $$PWD/qquickanimatorjob_p.h \ $$PWD/qquickanimatorcontroller_p.h \ - $$PWD/qquickprofiler_p.h + $$PWD/qquickprofiler_p.h \ + $$PWD/qquickfontmetrics_p.h diff --git a/tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro b/tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro new file mode 100644 index 0000000..452dd70 --- /dev/null +++ b/tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +TARGET = tst_quickfontmetrics +osx:CONFIG -= app_bundle + +SOURCES += tst_quickfontmetrics.cpp + +CONFIG += parallel_test + +QT += core gui qml quick-private testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp new file mode 100644 index 0000000..5e64858 --- /dev/null +++ b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include + +#include + +class tst_QuickFontMetrics : public QObject +{ + Q_OBJECT + +public: + tst_QuickFontMetrics(); + +private Q_SLOTS: + void properties(); + void functions_data(); + void functions(); +}; + +tst_QuickFontMetrics::tst_QuickFontMetrics() +{ +} + +void tst_QuickFontMetrics::properties() +{ + QStringList families = QFontDatabase().families().mid(0, 10); + QQuickFontMetrics metrics; + + foreach (const QString &family, families) { + QFont font(family); + QFontMetricsF expected(font); + + QSignalSpy spy(&metrics, SIGNAL(fontChanged(QFont))); + metrics.setFont(font); + QCOMPARE(spy.count(), 1); + + QCOMPARE(metrics.ascent(), expected.ascent()); + QCOMPARE(metrics.descent(), expected.descent()); + QCOMPARE(metrics.height(), expected.height()); + QCOMPARE(metrics.leading(), expected.leading()); + QCOMPARE(metrics.lineSpacing(), expected.lineSpacing()); + QCOMPARE(metrics.minimumLeftBearing(), expected.minLeftBearing()); + QCOMPARE(metrics.minimumRightBearing(), expected.minRightBearing()); + QCOMPARE(metrics.maximumCharacterWidth(), expected.maxWidth()); + QCOMPARE(metrics.xHeight(), expected.xHeight()); + QCOMPARE(metrics.averageCharacterWidth(), expected.averageCharWidth()); + QCOMPARE(metrics.underlinePosition(), expected.underlinePos()); + QCOMPARE(metrics.overlinePosition(), expected.overlinePos()); + QCOMPARE(metrics.strikeOutPosition(), expected.strikeOutPos()); + QCOMPARE(metrics.lineWidth(), expected.lineWidth()); + } +} + +Q_DECLARE_METATYPE(Qt::TextElideMode) + +void tst_QuickFontMetrics::functions_data() +{ + QTest::addColumn("text"); + QTest::addColumn("mode"); + QTest::addColumn("width"); + QTest::addColumn("flags"); + + QStringList strings; + strings << QString() + << QString::fromLatin1("") + << QString::fromLatin1("0") + << QString::fromLatin1("@@@@@@@") + << QString::fromLatin1("Hello"); + + QVector elideModes; + elideModes << Qt::ElideLeft << Qt::ElideMiddle << Qt::ElideRight << Qt::ElideNone; + + for (int stringIndex = 0; stringIndex < strings.size(); ++stringIndex) { + const QString string = strings.at(stringIndex); + + for (int elideModeIndex = 0; elideModeIndex < elideModes.size(); ++elideModeIndex) { + Qt::TextElideMode elideMode = static_cast(elideModes.at(elideModeIndex)); + + for (qreal width = 0; width < 100; width += 20) { + const QString tag = QString::fromLatin1("string=%1, mode=%2, width=%3").arg(string).arg(elideMode).arg(width); + QTest::newRow(qPrintable(tag)) << QString() << elideMode << width << 0; + } + } + } +} + +void tst_QuickFontMetrics::functions() +{ + QFETCH(QString, text); + QFETCH(Qt::TextElideMode, mode); + QFETCH(qreal, width); + QFETCH(int, flags); + + QQuickFontMetrics metrics; + QFontMetricsF expected = QFontMetricsF(QFont()); + + QCOMPARE(metrics.elidedText(text, mode, width, flags), expected.elidedText(text, mode, width, flags)); + QCOMPARE(metrics.advanceWidth(text), expected.width(text)); + QCOMPARE(metrics.boundingRect(text), expected.boundingRect(text)); + QCOMPARE(metrics.tightBoundingRect(text), expected.tightBoundingRect(text)); +} + +QTEST_MAIN(tst_QuickFontMetrics) + +#include "tst_quickfontmetrics.moc" diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 6c163d9..5f11da6 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -18,6 +18,7 @@ PRIVATETESTS += \ qquickapplication \ qquickbehaviors \ qquickfontloader \ + qquickfontmetrics \ qquickimageprovider \ qquickpath \ qquicksmoothedanimation \ -- 2.7.4