QFont: Don't invalidate engine unless request has been changed
authorKonstantin Ritt <ritt.ks@gmail.com>
Wed, 17 Oct 2012 11:31:33 +0000 (14:31 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 19 Oct 2012 16:04:36 +0000 (18:04 +0200)
This makes QFont do a "light" detach when the font attributes data has been changed.
The new test clearly shows that the engine is now shared between
two font instances after changing the kerning attribute.

Change-Id: I59db822f459f02d111686dba7101b98e361fada9
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/gui/text/qfont.cpp
src/gui/text/qfont_p.h
tests/auto/gui/text/qfont/qfont.pro
tests/auto/gui/text/qfont/tst_qfont.cpp

index 995d48d..2bc63cb 100644 (file)
@@ -649,6 +649,24 @@ void QFont::detach()
 }
 
 /*!
+    \internal
+    Detaches the font object from common font attributes data.
+    Call this instead of QFont::detach() if the only font attributes data
+    has been changed (underline, letterSpacing, kerning, etc.).
+*/
+void QFontPrivate::detachButKeepEngineData(QFont *font)
+{
+    if (font->d->ref.load() == 1)
+        return;
+
+    QFontEngineData *engineData = font->d->engineData;
+    if (engineData)
+        engineData->ref.ref();
+    font->d.detach();
+    font->d->engineData = engineData;
+}
+
+/*!
     Constructs a font object that uses the application's default font.
 
     \sa QGuiApplication::setFont(), QGuiApplication::font()
@@ -1149,7 +1167,7 @@ void QFont::setUnderline(bool enable)
     if ((resolve_mask & QFont::UnderlineResolved) && d->underline == enable)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->underline = enable;
     resolve_mask |= QFont::UnderlineResolved;
@@ -1175,7 +1193,7 @@ void QFont::setOverline(bool enable)
     if ((resolve_mask & QFont::OverlineResolved) && d->overline == enable)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->overline = enable;
     resolve_mask |= QFont::OverlineResolved;
@@ -1202,7 +1220,7 @@ void QFont::setStrikeOut(bool enable)
     if ((resolve_mask & QFont::StrikeOutResolved) && d->strikeOut == enable)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->strikeOut = enable;
     resolve_mask |= QFont::StrikeOutResolved;
@@ -1262,7 +1280,7 @@ void QFont::setKerning(bool enable)
     if ((resolve_mask & QFont::KerningResolved) && d->kerning == enable)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->kerning = enable;
     resolve_mask |= QFont::KerningResolved;
@@ -1512,7 +1530,7 @@ void QFont::setLetterSpacing(SpacingType type, qreal spacing)
         d->letterSpacing == newSpacing)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->letterSpacing = newSpacing;
     d->letterSpacingIsAbsolute = absoluteSpacing;
@@ -1562,7 +1580,7 @@ void QFont::setWordSpacing(qreal spacing)
         d->wordSpacing == newSpacing)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->wordSpacing = newSpacing;
     resolve_mask |= QFont::WordSpacingResolved;
@@ -1596,7 +1614,7 @@ void QFont::setCapitalization(Capitalization caps)
         capitalization() == caps)
         return;
 
-    detach();
+    QFontPrivate::detachButKeepEngineData(this);
 
     d->capital = caps;
     resolve_mask |= QFont::CapitalizationResolved;
@@ -1635,6 +1653,7 @@ void QFont::setRawMode(bool enable)
 {
     if ((bool) d->rawMode == enable) return;
 
+    // might change behavior, thus destroy engine data
     detach();
 
     d->rawMode = enable;
index f32b6e7..2a37b56 100644 (file)
@@ -185,6 +185,9 @@ public:
     }
 
     void resolve(uint mask, const QFontPrivate *other);
+
+    static void detachButKeepEngineData(QFont *font);
+
 private:
     QFontPrivate &operator=(const QFontPrivate &) { return *this; }
 };
index 86178f3..562294d 100644 (file)
@@ -2,6 +2,7 @@ CONFIG += testcase
 CONFIG += parallel_test
 TARGET = tst_qfont
 QT += testlib
+QT += core-private gui-private
 !contains(QT_CONFIG, no-widgets): QT += widgets
 SOURCES  += tst_qfont.cpp
 
index 287fd72..3fe23bf 100644 (file)
@@ -44,6 +44,7 @@
 
 
 #include <qfont.h>
+#include <private/qfont_p.h>
 #include <qfontdatabase.h>
 #include <qfontinfo.h>
 #include <qstringlist.h>
@@ -81,6 +82,8 @@ private slots:
     void styleName();
     void defaultFamily_data();
     void defaultFamily();
+
+    void sharing();
 };
 
 // Testing get/set functions
@@ -685,5 +688,45 @@ void tst_QFont::defaultFamily()
     QVERIFY2(isAcceptable, msgNotAcceptableFont(familyForHint, acceptableFamilies));
 }
 
+void tst_QFont::sharing()
+{
+    QFont f;
+    f.setStyleHint(QFont::Serif);
+    f.exactMatch(); // loads engine
+    QCOMPARE(QFontPrivate::get(f)->ref.load(), 1);
+    QVERIFY(QFontPrivate::get(f)->engineData);
+    QCOMPARE(QFontPrivate::get(f)->engineData->ref.load(), 1);
+
+    QFont f2(f);
+    QVERIFY(QFontPrivate::get(f2) == QFontPrivate::get(f));
+    QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2);
+    QVERIFY(QFontPrivate::get(f2)->engineData);
+    QVERIFY(QFontPrivate::get(f2)->engineData == QFontPrivate::get(f)->engineData);
+    QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1);
+
+    f2.setKerning(!f.kerning());
+    QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
+    QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1);
+    QVERIFY(QFontPrivate::get(f2)->engineData);
+    QVERIFY(QFontPrivate::get(f2)->engineData == QFontPrivate::get(f)->engineData);
+    QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 2);
+
+    f2 = f;
+    QVERIFY(QFontPrivate::get(f2) == QFontPrivate::get(f));
+    QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2);
+    QVERIFY(QFontPrivate::get(f2)->engineData);
+    QVERIFY(QFontPrivate::get(f2)->engineData == QFontPrivate::get(f)->engineData);
+    QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1);
+
+    if (f.pointSize() > 0)
+        f2.setPointSize(f.pointSize() * 2 / 3);
+    else
+        f2.setPixelSize(f.pixelSize() * 2 / 3);
+    QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
+    QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1);
+    QVERIFY(!QFontPrivate::get(f2)->engineData);
+    QVERIFY(QFontPrivate::get(f2)->engineData != QFontPrivate::get(f)->engineData);
+}
+
 QTEST_MAIN(tst_QFont)
 #include "tst_qfont.moc"