summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.h1
-rw-r--r--src/gui/text/qcssparser.cpp7
-rw-r--r--src/gui/text/qfont.cpp4
-rw-r--r--src/gui/text/qfont_s60.cpp2
-rw-r--r--src/gui/text/qfontdatabase.cpp14
-rw-r--r--src/gui/text/qfontdatabase_s60.cpp32
-rw-r--r--src/gui/text/qfontengine.cpp122
-rw-r--r--src/gui/text/qfontengine_ft.cpp3
-rw-r--r--src/gui/text/qfontengine_mac.mm8
-rw-r--r--src/gui/text/qfontengine_p.h16
-rw-r--r--src/gui/text/qfontengine_qpf.cpp4
-rw-r--r--src/gui/text/qfontengine_s60.cpp2
-rw-r--r--src/gui/text/qfontengine_s60_p.h2
-rw-r--r--src/gui/text/qfontengine_win.cpp107
-rw-r--r--src/gui/text/qfontengine_win_p.h4
-rw-r--r--src/gui/text/qfontengineglyphcache_p.h7
-rw-r--r--src/gui/text/qfontmetrics.cpp22
-rw-r--r--src/gui/text/qtextcontrol.cpp74
-rw-r--r--src/gui/text/qtextcontrol_p.h4
-rw-r--r--src/gui/text/qtextcontrol_p_p.h5
-rw-r--r--src/gui/text/qtextdocument.cpp10
-rw-r--r--src/gui/text/qtextdocument_p.cpp16
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp4
-rw-r--r--src/gui/text/qtextformat.cpp76
-rw-r--r--src/gui/text/qtextformat_p.h4
-rw-r--r--src/gui/text/qtextodfwriter.cpp13
26 files changed, 324 insertions, 239 deletions
diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h
index 2f8a746..438b291 100644
--- a/src/gui/text/qabstracttextdocumentlayout.h
+++ b/src/gui/text/qabstracttextdocumentlayout.h
@@ -122,6 +122,7 @@ protected:
QTextCharFormat format(int pos);
private:
+ friend class QTextControl;
friend class QTextDocument;
friend class QTextDocumentPrivate;
friend class QTextEngine;
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 6db86bd..93b9fc6 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -1129,19 +1129,22 @@ static bool setFontWeightFromValue(const Value &value, QFont *font)
static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font, int start = 0)
{
QString family;
+ bool shouldAddSpace = false;
for (int i = start; i < values.count(); ++i) {
const Value &v = values.at(i);
if (v.type == Value::TermOperatorComma) {
family += QLatin1Char(',');
+ shouldAddSpace = false;
continue;
}
const QString str = v.variant.toString();
if (str.isEmpty())
break;
+ if (shouldAddSpace)
+ family += QLatin1Char(' ');
family += str;
- family += QLatin1Char(' ');
+ shouldAddSpace = true;
}
- family = family.simplified();
if (family.isEmpty())
return false;
font->setFamily(family);
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 09dff89..72daafd 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -1613,7 +1613,8 @@ bool QFont::operator==(const QFont &f) const
&& f.d->underline == d->underline
&& f.d->overline == d->overline
&& f.d->strikeOut == d->strikeOut
- && f.d->kerning == d->kerning));
+ && f.d->kerning == d->kerning
+ && f.d->capital == d->capital));
}
@@ -1645,6 +1646,7 @@ bool QFont::operator<(const QFont &f) const
#ifdef Q_WS_X11
if (r1.addStyle != r2.addStyle) return r1.addStyle < r2.addStyle;
#endif // Q_WS_X11
+ if (f.d->capital != d->capital) return f.d->capital < d->capital;
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;
diff --git a/src/gui/text/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp
index 3439028..995f332 100644
--- a/src/gui/text/qfont_s60.cpp
+++ b/src/gui/text/qfont_s60.cpp
@@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** This file is part of the QtGui of the Qt Toolkit.
+** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 7e93aa0..e9c7b89 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -1482,13 +1482,13 @@ QString QFontDatabase::styleString(const QFontInfo &fontInfo)
and style will look attractive.
If the font family is available from two or more foundries the
- foundry name is included in the family name, e.g. "Helvetica
- [Adobe]" and "Helvetica [Cronyx]". When you specify a family you
- can either use the old hyphenated Qt 2.x "foundry-family" format,
- e.g. "Cronyx-Helvetica", or the new bracketed Qt 3.x "family
- [foundry]" format e.g. "Helvetica [Cronyx]". If the family has a
- foundry it is always returned, e.g. by families(), using the
- bracketed format.
+ foundry name is included in the family name; for example:
+ "Helvetica [Adobe]" and "Helvetica [Cronyx]". When you specify a
+ family, you can either use the old hyphenated "foundry-family"
+ format or the bracketed "family [foundry]" format; for example:
+ "Cronyx-Helvetica" or "Helvetica [Cronyx]". If the family has a
+ foundry it is always returned using the bracketed format, as is
+ the case with the value returned by families().
The font() function returns a QFont given a family, style and
point size.
diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp
index 84c631c..bf1600a 100644
--- a/src/gui/text/qfontdatabase_s60.cpp
+++ b/src/gui/text/qfontdatabase_s60.cpp
@@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** This file is part of the QtGui of the Qt Toolkit.
+** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
@@ -51,6 +51,9 @@
#include <private/qcore_symbian_p.h>
#if defined(QT_NO_FREETYPE)
#include <openfont.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file
+#endif // SYMBIAN_ENABLE_SPLIT_HEADERS
#endif
QT_BEGIN_NAMESPACE
@@ -136,6 +139,23 @@ QFontDatabaseS60StoreImplementation::~QFontDatabaseS60StoreImplementation()
m_heap->Close();
}
+#ifndef FNTSTORE_H_INLINES_SUPPORT_FMM
+/*
+ Workaround: fntstore.h has an inlined function 'COpenFont* CBitmapFont::OpenFont()'
+ that returns a private data member. The header will change between SDKs. But Qt has
+ to build on any SDK version and run on other versions of Symbian OS.
+ This function performs the needed pointer arithmetic to get the right COpenFont*
+*/
+COpenFont* OpenFontFromBitmapFont(const CBitmapFont* aBitmapFont)
+{
+ const TInt offsetIOpenFont = 92; // '_FOFF(CBitmapFont, iOpenFont)' ..if iOpenFont weren't private
+ const TUint valueIOpenFont = *(TUint*)PtrAdd(aBitmapFont, offsetIOpenFont);
+ return (valueIOpenFont & 1) ?
+ (COpenFont*)PtrAdd(aBitmapFont, valueIOpenFont & ~1) : // New behavior: iOpenFont is offset
+ (COpenFont*)valueIOpenFont; // Old behavior: iOpenFont is pointer
+}
+#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
+
const QFontEngineS60Extensions *QFontDatabaseS60StoreImplementation::extension(const QString &typeface) const
{
if (!m_extensions.contains(typeface)) {
@@ -144,8 +164,14 @@ const QFontEngineS60Extensions *QFontDatabaseS60StoreImplementation::extension(c
spec.iHeight = 1;
const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, spec);
Q_ASSERT(err == KErrNone && font);
- CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
- m_extensions.insert(typeface, new QFontEngineS60Extensions(font, bitmapFont->OpenFont()));
+ const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
+ COpenFont *openFont =
+#ifdef FNTSTORE_H_INLINES_SUPPORT_FMM
+ bitmapFont->openFont();
+#else
+ OpenFontFromBitmapFont(bitmapFont);
+#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
+ m_extensions.insert(typeface, new QFontEngineS60Extensions(font, openFont));
}
return m_extensions.value(typeface);
}
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 21b9cca..d364025 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -185,22 +185,11 @@ QFontEngine::QFontEngine()
QFontEngine::~QFontEngine()
{
- for (GlyphPointerHash::const_iterator it = m_glyphPointerHash.constBegin(),
- end = m_glyphPointerHash.constEnd(); it != end; ++it) {
- for (QList<QFontEngineGlyphCache*>::const_iterator it2 = it.value().constBegin(),
- end2 = it.value().constEnd(); it2 != end2; ++it2) {
- delete *it2;
- }
- }
- m_glyphPointerHash.clear();
- for (GlyphIntHash::const_iterator it = m_glyphIntHash.constBegin(),
- end = m_glyphIntHash.constEnd(); it != end; ++it) {
- for (QList<QFontEngineGlyphCache*>::const_iterator it2 = it.value().constBegin(),
- end2 = it.value().constEnd(); it2 != end2; ++it2) {
- delete *it2;
- }
+ for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(),
+ end = m_glyphCaches.constEnd(); it != end; ++it) {
+ delete it->cache;
}
- m_glyphIntHash.clear();
+ m_glyphCaches.clear();
qHBFreeFace(hbFace);
}
@@ -713,103 +702,30 @@ QByteArray QFontEngine::getSfntTable(uint tag) const
return table;
}
-void QFontEngine::expireGlyphCache()
-{
- if (m_glyphCacheQueue.count() > 10) { // hold only 10 caches in memory.
- QFontEngineGlyphCache *old = m_glyphCacheQueue.takeFirst();
- // remove the value from either of our hashes
- for (GlyphPointerHash::iterator i = m_glyphPointerHash.begin(); i != m_glyphPointerHash.end(); ++i) {
- QList<QFontEngineGlyphCache *> list = i.value();
- if (list.removeAll(old)) {
- if (list.isEmpty())
- m_glyphPointerHash.remove(i.key());
- else
- m_glyphPointerHash.insert(i.key(), list);
- break;
- }
- }
- for (GlyphIntHash::iterator i = m_glyphIntHash.begin(); i != m_glyphIntHash.end(); ++i) {
- QList<QFontEngineGlyphCache *> list = i.value();
- if (list.removeAll(old)) {
- if (list.isEmpty())
- m_glyphIntHash.remove(i.key());
- else
- m_glyphIntHash.insert(i.key(), list);
- break;
- }
- }
- delete old;
- }
-}
-
void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data)
{
Q_ASSERT(data);
- QList<QFontEngineGlyphCache*> items = m_glyphPointerHash.value(key);
-
- for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) {
- QFontEngineGlyphCache *c = *it;
- if (qtransform_equals_no_translate(c->m_transform, data->m_transform)) {
- if (c == data)
- return;
- items.removeAll(c);
- delete c;
- break;
- }
- }
- items.append(data);
- m_glyphPointerHash.insert(key, items);
- m_glyphCacheQueue.append(data);
- expireGlyphCache();
-}
+ GlyphCacheEntry entry = { key, data };
+ if (m_glyphCaches.contains(entry))
+ return;
-void QFontEngine::setGlyphCache(QFontEngineGlyphCache::Type key, QFontEngineGlyphCache *data)
-{
- Q_ASSERT(data);
- QList<QFontEngineGlyphCache*> items = m_glyphIntHash.value(key);
-
- for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) {
- QFontEngineGlyphCache *c = *it;
- if (qtransform_equals_no_translate(c->m_transform, data->m_transform)) {
- if (c == data)
- return;
- items.removeAll(c);
- delete c;
- break;
- }
- }
- items.append(data);
- m_glyphIntHash.insert(key, items);
+ // Limit the glyph caches to 4. This covers all 90 degree rotations and limits
+ // memory use when there is continous or random rotation
+ if (m_glyphCaches.size() == 4)
+ delete m_glyphCaches.takeLast().cache;
- m_glyphCacheQueue.append(data);
- expireGlyphCache();
-}
+ m_glyphCaches.push_front(entry);
-QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, const QTransform &transform) const
-{
- QList<QFontEngineGlyphCache*> items = m_glyphPointerHash.value(key);
-
- for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) {
- QFontEngineGlyphCache *c = *it;
- if (qtransform_equals_no_translate(c->m_transform, transform)) {
- m_glyphCacheQueue.removeAll(c); // last used, move it up
- m_glyphCacheQueue.append(c);
- return c;
- }
- }
- return 0;
}
-QFontEngineGlyphCache *QFontEngine::glyphCache(QFontEngineGlyphCache::Type key, const QTransform &transform) const
+QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const
{
- QList<QFontEngineGlyphCache*> items = m_glyphIntHash.value(key);
-
- for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) {
- QFontEngineGlyphCache *c = *it;
- if (qtransform_equals_no_translate(c->m_transform, transform)) {
- m_glyphCacheQueue.removeAll(c); // last used, move it up
- m_glyphCacheQueue.append(c);
+ for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) {
+ QFontEngineGlyphCache *c = it->cache;
+ if (key == it->context
+ && type == c->cacheType()
+ && qtransform_equals_no_translate(c->m_transform, transform)) {
return c;
}
}
@@ -1370,8 +1286,8 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
for (int i = 0; i < len; ++i) {
bool surrogate = (str[i].unicode() >= 0xd800 && str[i].unicode() < 0xdc00 && i < len-1
&& str[i+1].unicode() >= 0xdc00 && str[i+1].unicode() < 0xe000);
- if (glyphs->glyphs[glyph_pos] == 0) {
+ if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) {
QGlyphLayoutInstance tmp = glyphs->instance(glyph_pos);
for (int x = 1; x < engines.size(); ++x) {
QFontEngine *engine = engines.at(x);
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index 4041717..293eac7 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -755,9 +755,8 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph
load_flags = FT_LOAD_NO_BITMAP;
// apply our matrix to this, but note that the metrics will not be affected by this.
- FT_Matrix matrix = freetype->matrix;
FT_Face face = lockFace();
- matrix = this->matrix;
+ FT_Matrix matrix = this->matrix;
FT_Matrix_Multiply(&set->transformationMatrix, &matrix);
FT_Set_Transform(face, &matrix, 0);
freetype->matrix = matrix;
diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm
index a4e7c04..a75d70f 100644
--- a/src/gui/text/qfontengine_mac.mm
+++ b/src/gui/text/qfontengine_mac.mm
@@ -404,7 +404,9 @@ QFixed QCoreTextFontEngine::ascent() const
}
QFixed QCoreTextFontEngine::descent() const
{
- return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil();
+ // subtract a pixel to even out the historical +1 in QFontMetrics::height().
+ // Fix in Qt 5.
+ return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil() - 1;
}
QFixed QCoreTextFontEngine::leading() const
{
@@ -1406,7 +1408,9 @@ QFixed QFontEngineMac::ascent() const
QFixed QFontEngineMac::descent() const
{
- return m_descent;
+ // subtract a pixel to even out the historical +1 in QFontMetrics::height().
+ // Fix in Qt 5.
+ return m_descent - 1;
}
QFixed QFontEngineMac::leading() const
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 728c344..a9883b4 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -56,6 +56,7 @@
#include "QtCore/qglobal.h"
#include "QtCore/qatomic.h"
#include <QtCore/qvarlengtharray.h>
+#include <QtCore/QLinkedList>
#include "private/qtextengine_p.h"
#include "private/qfont_p.h"
@@ -219,9 +220,7 @@ public:
virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints);
void setGlyphCache(void *key, QFontEngineGlyphCache *data);
- void setGlyphCache(QFontEngineGlyphCache::Type key, QFontEngineGlyphCache *data);
- QFontEngineGlyphCache *glyphCache(void *key, const QTransform &transform) const;
- QFontEngineGlyphCache *glyphCache(QFontEngineGlyphCache::Type key, const QTransform &transform) const;
+ QFontEngineGlyphCache *glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const;
static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode);
@@ -254,12 +253,13 @@ protected:
static const QVector<QRgb> &grayPalette();
private:
- /// remove old entries from the glyph cache. Helper method for the setGlyphCache ones.
- void expireGlyphCache();
+ struct GlyphCacheEntry {
+ void *context;
+ QFontEngineGlyphCache *cache;
+ bool operator==(const GlyphCacheEntry &other) { return context == other.context && cache == other.cache; }
+ };
- GlyphPointerHash m_glyphPointerHash;
- GlyphIntHash m_glyphIntHash;
- mutable QList<QFontEngineGlyphCache*> m_glyphCacheQueue;
+ mutable QLinkedList<GlyphCacheEntry> m_glyphCaches;
};
inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2)
diff --git a/src/gui/text/qfontengine_qpf.cpp b/src/gui/text/qfontengine_qpf.cpp
index 94974fc..f978bd8 100644
--- a/src/gui/text/qfontengine_qpf.cpp
+++ b/src/gui/text/qfontengine_qpf.cpp
@@ -938,7 +938,7 @@ void QFontEngineQPF::loadGlyph(glyph_t glyph)
g.advance = qRound(metrics.xoff);
QT_WRITE(fd, &g, sizeof(g));
- QT_WRITE(fd, img.bits(), img.numBytes());
+ QT_WRITE(fd, img.bits(), img.byteCount());
glyphPos = oldSize - glyphDataOffset;
#if 0 && defined(DEBUG_FONTENGINE)
@@ -948,7 +948,7 @@ void QFontEngineQPF::loadGlyph(glyph_t glyph)
quint32 *gmap = (quint32 *)(fontData + glyphMapOffset);
gmap[glyph] = qToBigEndian(glyphPos);
- glyphDataSize = glyphPos + sizeof(g) + img.numBytes();
+ glyphDataSize = glyphPos + sizeof(g) + img.byteCount();
quint32 *blockSizePtr = (quint32 *)(fontData + glyphDataOffset - 4);
*blockSizePtr = qToBigEndian(glyphDataSize);
}
diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp
index 88ae8f6..e279ad2 100644
--- a/src/gui/text/qfontengine_s60.cpp
+++ b/src/gui/text/qfontengine_s60.cpp
@@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** This file is part of the QtGui of the Qt Toolkit.
+** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h
index 746f929..460b5ee 100644
--- a/src/gui/text/qfontengine_s60_p.h
+++ b/src/gui/text/qfontengine_s60_p.h
@@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** This file is part of the QtGui of the Qt Toolkit.
+** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp
index 6c367ab..7ec8e31 100644
--- a/src/gui/text/qfontengine_win.cpp
+++ b/src/gui/text/qfontengine_win.cpp
@@ -485,61 +485,80 @@ glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs)
return glyph_metrics_t(0, -tm.tmAscent, w, tm.tmHeight, w, 0);
}
+#ifndef Q_WS_WINCE
+bool QFontEngineWin::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
+{
+ Q_ASSERT(metrics != 0);
+
+ HDC hdc = shared_dc();
+
+ GLYPHMETRICS gm;
+ DWORD res = 0;
+ MAT2 mat;
+ mat.eM11.value = mat.eM22.value = 1;
+ mat.eM11.fract = mat.eM22.fract = 0;
+ mat.eM21.value = mat.eM12.value = 0;
+ mat.eM21.fract = mat.eM12.fract = 0;
+
+ if (t.type() > QTransform::TxTranslate) {
+ // We need to set the transform using the HDC's world
+ // matrix rather than using the MAT2 above, because the
+ // results provided when transforming via MAT2 does not
+ // match the glyphs that are drawn using a WorldTransform
+ XFORM xform;
+ xform.eM11 = t.m11();
+ xform.eM12 = t.m12();
+ xform.eM21 = t.m21();
+ xform.eM22 = t.m22();
+ xform.eDx = 0;
+ xform.eDy = 0;
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ }
+
+ uint format = GGO_METRICS;
+ if (ttf)
+ format |= GGO_GLYPH_INDEX;
+ res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
+
+ if (t.type() > QTransform::TxTranslate) {
+ XFORM xform;
+ xform.eM11 = xform.eM22 = 1;
+ xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
+ SetWorldTransform(hdc, &xform);
+ SetGraphicsMode(hdc, GM_COMPATIBLE);
+ }
+
+ if (res != GDI_ERROR) {
+ *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
+ (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
+ return true;
+ } else {
+ return false;
+ }
+}
+#endif
glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
{
#ifndef Q_WS_WINCE
- GLYPHMETRICS gm;
-
HDC hdc = shared_dc();
SelectObject(hdc, hfont);
- if (!ttf) {
+
+ glyph_metrics_t glyphMetrics;
+ bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
+
+ if (!ttf && !success) {
+ // Bitmap fonts
wchar_t ch = glyph;
ABCFLOAT abc;
GetCharABCWidthsFloat(hdc, ch, ch, &abc);
int width = qRound(abc.abcfB);
- return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
- } else {
- DWORD res = 0;
- MAT2 mat;
- mat.eM11.value = mat.eM22.value = 1;
- mat.eM11.fract = mat.eM22.fract = 0;
- mat.eM21.value = mat.eM12.value = 0;
- mat.eM21.fract = mat.eM12.fract = 0;
-
- if (t.type() > QTransform::TxTranslate) {
- // We need to set the transform using the HDC's world
- // matrix rather than using the MAT2 above, because the
- // results provided when transforming via MAT2 does not
- // match the glyphs that are drawn using a WorldTransform
- XFORM xform;
- xform.eM11 = t.m11();
- xform.eM12 = t.m12();
- xform.eM21 = t.m21();
- xform.eM22 = t.m22();
- xform.eDx = 0;
- xform.eDy = 0;
- SetGraphicsMode(hdc, GM_ADVANCED);
- SetWorldTransform(hdc, &xform);
- }
-
- res = GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 0, &mat);
-
- if (t.type() > QTransform::TxTranslate) {
- XFORM xform;
- xform.eM11 = xform.eM22 = 1;
- xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
- SetWorldTransform(hdc, &xform);
- SetGraphicsMode(hdc, GM_COMPATIBLE);
- }
-
- if (res != GDI_ERROR) {
- return glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
- (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
- }
+ return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
}
- return glyph_metrics_t();
+
+ return glyphMetrics;
#else
HDC hdc = shared_dc();
HGDIOBJ oldFont = SelectObject(hdc, hfont);
@@ -1135,7 +1154,7 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin
{
ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
}
-
+
SelectObject(hdc, old_font);
return ni;
}
diff --git a/src/gui/text/qfontengine_win_p.h b/src/gui/text/qfontengine_win_p.h
index 9c4b0a9..bab71c9 100644
--- a/src/gui/text/qfontengine_win_p.h
+++ b/src/gui/text/qfontengine_win_p.h
@@ -109,6 +109,10 @@ public:
int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const;
void getCMap();
+#ifndef Q_WS_WINCE
+ bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;
+#endif
+
QString _name;
HFONT hfont;
LOGFONT logfont;
diff --git a/src/gui/text/qfontengineglyphcache_p.h b/src/gui/text/qfontengineglyphcache_p.h
index e04f4ac..c6112ba 100644
--- a/src/gui/text/qfontengineglyphcache_p.h
+++ b/src/gui/text/qfontengineglyphcache_p.h
@@ -75,17 +75,20 @@ QT_BEGIN_NAMESPACE
class QFontEngineGlyphCache
{
public:
- QFontEngineGlyphCache(const QTransform &matrix) : m_transform(matrix) { }
-
enum Type {
Raster_RGBMask,
Raster_A8,
Raster_Mono
};
+ QFontEngineGlyphCache(const QTransform &matrix, Type type) : m_transform(matrix), m_type(type) { }
+
virtual ~QFontEngineGlyphCache() { }
+ Type cacheType() const { return m_type; }
+
QTransform m_transform;
+ QFontEngineGlyphCache::Type m_type;
};
typedef QHash<void *, QList<QFontEngineGlyphCache *> > GlyphPointerHash;
typedef QHash<int, QList<QFontEngineGlyphCache *> > GlyphIntHash;
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index b8c1b33..3d3f1e1 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -1367,10 +1367,13 @@ qreal QFontMetricsF::rightBearing(QChar ch) const
*/
qreal QFontMetricsF::width(const QString &text) const
{
+ int pos = text.indexOf(QLatin1Char('\x9c'));
+ int len = (pos != -1) ? pos : text.length();
+
QTextEngine layout(text, d.data());
layout.ignoreBidi = true;
layout.itemize();
- return layout.width(0, text.length()).toReal();
+ return layout.width(0, len).toReal();
}
/*!
@@ -1587,7 +1590,7 @@ QRectF QFontMetricsF::boundingRect(const QRectF &rect, int flags, const QString&
*/
QSizeF QFontMetricsF::size(int flags, const QString &text, int tabStops, int *tabArray) const
{
- return boundingRect(QRectF(), flags, text, tabStops, tabArray).size();
+ return boundingRect(QRectF(), flags | Qt::TextLongestVariant, text, tabStops, tabArray).size();
}
/*!
@@ -1642,7 +1645,20 @@ QRectF QFontMetricsF::tightBoundingRect(const QString &text) const
*/
QString QFontMetricsF::elidedText(const QString &text, Qt::TextElideMode mode, qreal width, int flags) const
{
- QStackTextEngine engine(text, QFont(d.data()));
+ QString _text = text;
+ if (!(flags & Qt::TextLongestVariant)) {
+ int posA = 0;
+ int posB = _text.indexOf(QLatin1Char('\x9c'));
+ while (posB >= 0) {
+ QString portion = _text.mid(posA, posB - posA);
+ if (size(flags, portion).width() <= width)
+ return portion;
+ posA = posB + 1;
+ posB = _text.indexOf(QLatin1Char('\x9c'), posA);
+ }
+ _text = _text.mid(posA);
+ }
+ QStackTextEngine engine(_text, QFont(d.data()));
return engine.elidedText(mode, QFixed::fromReal(width), flags);
}
diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp
index 9497b6f..f96f66b 100644
--- a/src/gui/text/qtextcontrol.cpp
+++ b/src/gui/text/qtextcontrol.cpp
@@ -55,6 +55,7 @@
#include <qstyle.h>
#include <qtimer.h>
#include "private/qtextdocumentlayout_p.h"
+#include "private/qabstracttextdocumentlayout_p.h"
#include "private/qtextedit_p.h"
#include "qtextdocument.h"
#include "private/qtextdocument_p.h"
@@ -126,6 +127,7 @@ QTextControlPrivate::QTextControlPrivate()
#endif
isEnabled(true),
hadSelectionOnMousePress(false),
+ ignoreUnusedNavigationEvents(false),
openExternalLinks(false)
{}
@@ -264,19 +266,25 @@ bool QTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
cursor.setVisualNavigation(visualNavigation);
q->ensureCursorVisible();
+ bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
+ bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ ignoreNavigationEvents = ignoreNavigationEvents || QApplication::keypadNavigationEnabled();
+ isNavigationEvent = isNavigationEvent ||
+ (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
+ && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
+#else
+ isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
+#endif
+
if (moved) {
if (cursor.position() != oldCursorPos)
emit q->cursorPositionChanged();
emit q->microFocusChanged();
- }
-#ifdef QT_KEYPAD_NAVIGATION
- else if (QApplication::keypadNavigationEnabled()
- && ((e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)
- || QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
- && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))) {
+ } else if (ignoreNavigationEvents && isNavigationEvent) {
return false;
}
-#endif
selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
@@ -911,7 +919,7 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte
break;
case QEvent::MouseButtonPress: {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
- d->mousePressEvent(ev->button(), matrix.map(ev->pos()), ev->modifiers(),
+ d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
ev->buttons(), ev->globalPos());
break; }
case QEvent::MouseMove: {
@@ -979,7 +987,7 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte
#ifndef QT_NO_GRAPHICSVIEW
case QEvent::GraphicsSceneMousePress: {
QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
- d->mousePressEvent(ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
ev->screenPos());
break; }
case QEvent::GraphicsSceneMouseMove: {
@@ -1296,7 +1304,9 @@ QVariant QTextControl::loadResource(int type, const QUrl &name)
void QTextControlPrivate::_q_updateBlock(const QTextBlock &block)
{
Q_Q(QTextControl);
- emit q->updateRequest(q->blockBoundingRect(block));
+ QRectF br = q->blockBoundingRect(block);
+ br.setRight(qreal(INT_MAX)); // the block might have shrunk
+ emit q->updateRequest(br);
}
QRectF QTextControlPrivate::rectForPosition(int position) const
@@ -1465,7 +1475,7 @@ QRectF QTextControl::selectionRect() const
return selectionRect(d->cursor);
}
-void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
+void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
Qt::MouseButtons buttons, const QPoint &globalPos)
{
Q_Q(QTextControl);
@@ -1479,11 +1489,11 @@ void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF
cursor.clearSelection();
}
}
- if (!(button & Qt::LeftButton))
- return;
-
- if (!((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable)))
- return;
+ if (!(button & Qt::LeftButton) ||
+ !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
+ e->ignore();
+ return;
+ }
cursorIsFocusIndicator = false;
const QTextCursor oldSelection = cursor;
@@ -1507,8 +1517,10 @@ void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF
trippleClickTimer.stop();
} else {
int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
- if (cursorPos == -1)
+ if (cursorPos == -1) {
+ e->ignore();
return;
+ }
#if !defined(QT_NO_IM)
QTextLayout *layout = cursor.block().layout();
@@ -1519,8 +1531,10 @@ void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF
button, buttons, modifiers);
ctx->mouseHandler(cursorPos - cursor.position(), &ev);
}
- if (!layout->preeditAreaText().isEmpty())
+ if (!layout->preeditAreaText().isEmpty()) {
+ e->ignore();
return;
+ }
}
#endif
if (modifiers == Qt::ShiftModifier) {
@@ -1835,8 +1849,8 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
|| e->preeditString() != cursor.block().layout()->preeditAreaText()
|| e->replacementLength() > 0;
+ cursor.beginEditBlock();
if (isGettingInput) {
- cursor.beginEditBlock();
cursor.removeSelectedText();
}
@@ -1862,7 +1876,8 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
QTextBlock block = cursor.block();
QTextLayout *layout = block.layout();
- layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
+ if (isGettingInput)
+ layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
QList<QTextLayout::FormatRange> overrides;
preeditCursor = e->preeditString().length();
hideCursor = false;
@@ -1883,9 +1898,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
}
}
layout->setAdditionalFormats(overrides);
-
- if (isGettingInput)
- cursor.endEditBlock();
+ cursor.endEditBlock();
}
QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
@@ -2257,6 +2270,18 @@ bool QTextControl::openExternalLinks() const
return d->openExternalLinks;
}
+bool QTextControl::ignoreUnusedNavigationEvents() const
+{
+ Q_D(const QTextControl);
+ return d->ignoreUnusedNavigationEvents;
+}
+
+void QTextControl::setIgnoreUnusedNavigationEvents(bool ignore)
+{
+ Q_D(QTextControl);
+ d->ignoreUnusedNavigationEvents = ignore;
+}
+
void QTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
{
Q_D(QTextControl);
@@ -2313,6 +2338,9 @@ void QTextControl::print(QPrinter *printer) const
tempDoc->setUseDesignMetrics(doc->useDesignMetrics());
QTextCursor(tempDoc).insertFragment(d->cursor.selection());
doc = tempDoc;
+
+ // copy the custom object handlers
+ doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers;
}
doc->print(printer);
delete tempDoc;
diff --git a/src/gui/text/qtextcontrol_p.h b/src/gui/text/qtextcontrol_p.h
index 263af31..bc8e063 100644
--- a/src/gui/text/qtextcontrol_p.h
+++ b/src/gui/text/qtextcontrol_p.h
@@ -95,6 +95,7 @@ class Q_GUI_EXPORT QTextControl : public QObject
Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)
+ Q_PROPERTY(bool ignoreUnusedNavigationEvents READ ignoreUnusedNavigationEvents WRITE setIgnoreUnusedNavigationEvents)
public:
explicit QTextControl(QObject *parent = 0);
explicit QTextControl(const QString &text, QObject *parent = 0);
@@ -163,6 +164,9 @@ public:
void setOpenExternalLinks(bool open);
bool openExternalLinks() const;
+ void setIgnoreUnusedNavigationEvents(bool ignore);
+ bool ignoreUnusedNavigationEvents() const;
+
void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
bool canPaste() const;
diff --git a/src/gui/text/qtextcontrol_p_p.h b/src/gui/text/qtextcontrol_p_p.h
index ca9db9f..c230512 100644
--- a/src/gui/text/qtextcontrol_p_p.h
+++ b/src/gui/text/qtextcontrol_p_p.h
@@ -131,10 +131,10 @@ public:
QString anchorForCursor(const QTextCursor &anchor) const;
void keyPressEvent(QKeyEvent *e);
- void mousePressEvent(Qt::MouseButton button, const QPointF &pos,
+ void mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos,
Qt::KeyboardModifiers modifiers,
Qt::MouseButtons buttons,
- const QPoint &globalPos = QPoint());
+ const QPoint &globalPos);
void mouseMoveEvent(Qt::MouseButtons buttons, const QPointF &pos);
void mouseReleaseEvent(Qt::MouseButton button, const QPointF &pos);
void mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos);
@@ -206,6 +206,7 @@ public:
QString anchorOnMousePress;
bool hadSelectionOnMousePress;
+ bool ignoreUnusedNavigationEvents;
bool openExternalLinks;
QString linkToCopy;
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 1aad385..523dd18 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -64,6 +64,7 @@
#include "qtextdocument_p.h"
#include <private/qprinter_p.h>
+#include <private/qabstracttextdocumentlayout_p.h>
#include <limits.h>
@@ -1722,6 +1723,9 @@ void QTextDocument::print(QPrinter *printer) const
QAbstractTextDocumentLayout *layout = doc->documentLayout();
layout->setPaintDevice(p.device());
+ // copy the custom object handlers
+ layout->d_func()->handlers = documentLayout()->d_func()->handlers;
+
int dpiy = p.device()->logicalDpiY();
int margin = 0;
if (printer->fullPage() && !printer->d_func()->hasCustomPageMargins) {
@@ -1763,6 +1767,12 @@ void QTextDocument::print(QPrinter *printer) const
fromPage = qMax(1, fromPage);
toPage = qMin(doc->pageCount(), toPage);
+ if (toPage < fromPage) {
+ // if the user entered a page range outside the actual number
+ // of printable pages, just return
+ return;
+ }
+
if (printer->pageOrder() == QPrinter::LastPageFirst) {
int tmp = fromPage;
fromPage = toPage;
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 2ad6512..b015198 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -870,6 +870,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
undoEnabled = false;
beginEditBlock();
+ int editPos = -1;
while (1) {
if (undo)
--undoState;
@@ -881,11 +882,13 @@ int QTextDocumentPrivate::undoRedo(bool undo)
remove(c.pos, c.length, (QTextUndoCommand::Operation)c.operation);
PMDEBUG(" erase: from %d, length %d", c.pos, c.length);
c.command = QTextUndoCommand::Removed;
+ editPos = c.pos;
break;
case QTextUndoCommand::Removed:
PMDEBUG(" insert: format %d (from %d, length %d, strpos=%d)", c.format, c.pos, c.length, c.strPos);
insert_string(c.pos, c.strPos, c.length, c.format, (QTextUndoCommand::Operation)c.operation);
c.command = QTextUndoCommand::Inserted;
+ editPos = c.pos + c.length;
break;
case QTextUndoCommand::BlockInserted:
case QTextUndoCommand::BlockAdded:
@@ -895,6 +898,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
c.command = QTextUndoCommand::BlockRemoved;
else
c.command = QTextUndoCommand::BlockDeleted;
+ editPos = c.pos;
break;
case QTextUndoCommand::BlockRemoved:
case QTextUndoCommand::BlockDeleted:
@@ -905,6 +909,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
c.command = QTextUndoCommand::BlockInserted;
else
c.command = QTextUndoCommand::BlockAdded;
+ editPos = c.pos + 1;
break;
case QTextUndoCommand::CharFormatChanged: {
resetBlockRevision = -1; // ## TODO
@@ -915,6 +920,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
int oldFormat = it.value()->format;
setCharFormat(c.pos, c.length, formats.charFormat(c.format));
c.format = oldFormat;
+ editPos = c.pos + c.length;
break;
}
case QTextUndoCommand::BlockFormatChanged: {
@@ -937,6 +943,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
group->blockFormatChanged(it);
}
documentChange(it.position(), it.length());
+ editPos = -1;
break;
}
case QTextUndoCommand::GroupFormatChange: {
@@ -946,6 +953,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
int oldFormat = formats.objectFormatIndex(c.objectIndex);
changeObjectFormat(object, c.format);
c.format = oldFormat;
+ editPos = -1;
break;
}
case QTextUndoCommand::Custom:
@@ -954,6 +962,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
c.custom->undo();
else
c.custom->redo();
+ editPos = -1;
break;
default:
Q_ASSERT(false);
@@ -979,8 +988,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
break;
}
undoEnabled = true;
- int editPos = -1;
- if (docChangeFrom >= 0) {
+ if (editPos < 0 && docChangeFrom >= 0) {
editPos = qMin(docChangeFrom + docChangeLength, length() - 1);
}
endEditBlock();
@@ -1114,9 +1122,11 @@ void QTextDocumentPrivate::endEditBlock()
return;
if (undoEnabled && undoState > 0) {
+ const bool wasBlocking = !undoStack[undoState - 1].block_end;
if (undoStack[undoState - 1].block_part) {
undoStack[undoState - 1].block_end = true;
- emit document()->undoCommandAdded();
+ if (wasBlocking)
+ emit document()->undoCommandAdded();
}
}
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index 73434b1..2604879 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -1448,13 +1448,13 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
painter->fillRect(r, brush);
break;
case QTextListFormat::ListCircle:
- painter->drawEllipse(r);
+ painter->setPen(QPen(brush, 0));
+ painter->drawEllipse(r.translated(0.5, 0.5)); // pixel align for sharper rendering
break;
case QTextListFormat::ListDisc:
painter->setBrush(brush);
painter->setPen(Qt::NoPen);
painter->drawEllipse(r);
- painter->setBrush(Qt::NoBrush);
break;
case QTextListFormat::ListStyleUndefined:
break;
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index d05d9e5..deda39f 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -265,21 +265,55 @@ private:
friend QDataStream &operator>>(QDataStream &, QTextFormat &);
};
-static uint variantHash(const QVariant &variant)
+// this is only safe if sizeof(int) == sizeof(float)
+static inline uint hash(float d)
{
- switch (variant.userType()) {
- case QVariant::Invalid: return 0;
- case QVariant::Bool: return variant.toBool();
- case QVariant::Int: return variant.toInt();
- case QMetaType::Float: return static_cast<int>(variant.toFloat());
- case QVariant::Double: return static_cast<int>(variant.toDouble());
+ return reinterpret_cast<uint&>(d);
+}
+
+static inline uint hash(const QColor &color)
+{
+ return (color.isValid()) ? color.rgba() : 0x234109;
+}
+
+static inline uint hash(const QPen &pen)
+{
+ return hash(pen.color()) + hash(pen.widthF());
+}
+
+static inline uint hash(const QBrush &brush)
+{
+ return hash(brush.color()) + (brush.style() << 3);
+}
+
+static inline uint variantHash(const QVariant &variant)
+{
+ // simple and fast hash functions to differentiate between type and value
+ switch (variant.userType()) { // sorted by occurrence frequency
case QVariant::String: return qHash(variant.toString());
- case QVariant::Color: return qHash(qvariant_cast<QColor>(variant).rgb());
+ case QVariant::Double: return hash(variant.toDouble());
+ case QVariant::Int: return 0x811890 + variant.toInt();
+ case QVariant::Brush:
+ return 0x01010101 + hash(qvariant_cast<QBrush>(variant));
+ case QVariant::Bool: return 0x371818 + variant.toBool();
+ case QVariant::Pen: return 0x02020202 + hash(qvariant_cast<QPen>(variant));
+ case QVariant::List:
+ return 0x8377 + qvariant_cast<QVariantList>(variant).count();
+ case QVariant::Color: return hash(qvariant_cast<QColor>(variant));
+ case QVariant::TextLength:
+ return 0x377 + hash(qvariant_cast<QTextLength>(variant).rawValue());
+ case QMetaType::Float: return hash(variant.toFloat());
+ case QVariant::Invalid: return 0;
default: break;
}
return qHash(variant.typeName());
}
+static inline int getHash(const QTextFormatPrivate *d, int format)
+{
+ return (d ? d->hash() : 0) + format;
+}
+
uint QTextFormatPrivate::recalcHash() const
{
hashValue = 0;
@@ -3033,13 +3067,15 @@ QTextFormatCollection::~QTextFormatCollection()
int QTextFormatCollection::indexForFormat(const QTextFormat &format)
{
- uint hash = format.d ? format.d->hash() : 0;
- if (hashes.contains(hash)) {
- for (int i = 0; i < formats.size(); ++i) {
- if (formats.at(i) == format)
- return i;
+ uint hash = getHash(format.d, format.format_type);
+ QMultiHash<uint, int>::const_iterator i = hashes.find(hash);
+ while (i != hashes.end() && i.key() == hash) {
+ if (formats.value(i.value()) == format) {
+ return i.value();
}
+ ++i;
}
+
int idx = formats.size();
formats.append(format);
@@ -3049,7 +3085,7 @@ int QTextFormatCollection::indexForFormat(const QTextFormat &format)
f.d = new QTextFormatPrivate;
f.d->resolveFont(defaultFnt);
- hashes.insert(hash);
+ hashes.insert(hash, idx);
} QT_CATCH(...) {
formats.pop_back();
@@ -3060,11 +3096,13 @@ int QTextFormatCollection::indexForFormat(const QTextFormat &format)
bool QTextFormatCollection::hasFormatCached(const QTextFormat &format) const
{
- uint hash = format.d ? format.d->hash() : 0;
- if (hashes.contains(hash)) {
- for (int i = 0; i < formats.size(); ++i)
- if (formats.at(i) == format)
- return true;
+ uint hash = getHash(format.d, format.format_type);
+ QMultiHash<uint, int>::const_iterator i = hashes.find(hash);
+ while (i != hashes.end() && i.key() == hash) {
+ if (formats.value(i.value()) == format) {
+ return true;
+ }
+ ++i;
}
return false;
}
diff --git a/src/gui/text/qtextformat_p.h b/src/gui/text/qtextformat_p.h
index c796343..73ca0ce 100644
--- a/src/gui/text/qtextformat_p.h
+++ b/src/gui/text/qtextformat_p.h
@@ -55,7 +55,7 @@
#include "QtGui/qtextformat.h"
#include "QtCore/qvector.h"
-#include "QtCore/qset.h"
+#include "QtCore/qhash.h"
QT_BEGIN_NAMESPACE
@@ -97,7 +97,7 @@ public:
FormatVector formats;
QVector<qint32> objFormats;
- QSet<uint> hashes;
+ QMultiHash<uint,int> hashes;
inline QFont defaultFont() const { return defaultFnt; }
void setDefaultFont(const QFont &f);
diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp
index 9b7e8de..1bd4dd6 100644
--- a/src/gui/text/qtextodfwriter.cpp
+++ b/src/gui/text/qtextodfwriter.cpp
@@ -447,18 +447,19 @@ void QTextOdfWriter::writeBlockFormat(QXmlStreamWriter &writer, QTextBlockFormat
writer.writeStartElement(styleNS, QString::fromLatin1("paragraph-properties"));
if (format.hasProperty(QTextFormat::BlockAlignment)) {
+ const Qt::Alignment alignment = format.alignment() & Qt::AlignHorizontal_Mask;
QString value;
- if (format.alignment() == Qt::AlignLeading)
+ if (alignment == Qt::AlignLeading)
value = QString::fromLatin1("start");
- else if (format.alignment() == Qt::AlignTrailing)
+ else if (alignment == Qt::AlignTrailing)
value = QString::fromLatin1("end");
- else if (format.alignment() == (Qt::AlignLeft | Qt::AlignAbsolute))
+ else if (alignment == (Qt::AlignLeft | Qt::AlignAbsolute))
value = QString::fromLatin1("left");
- else if (format.alignment() == (Qt::AlignRight | Qt::AlignAbsolute))
+ else if (alignment == (Qt::AlignRight | Qt::AlignAbsolute))
value = QString::fromLatin1("right");
- else if (format.alignment() == Qt::AlignHCenter)
+ else if (alignment == Qt::AlignHCenter)
value = QString::fromLatin1("center");
- else if (format.alignment() == Qt::AlignJustify)
+ else if (alignment == Qt::AlignJustify)
value = QString::fromLatin1("justify");
else
qWarning() << "QTextOdfWriter: unsupported paragraph alignment; " << format.alignment();