summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qcssparser.cpp2
-rw-r--r--src/gui/text/qfont.cpp16
-rw-r--r--src/gui/text/qfont.h23
-rw-r--r--src/gui/text/qfont_s60.cpp4
-rw-r--r--src/gui/text/qfontdatabase.cpp2
-rw-r--r--src/gui/text/qfontdatabase_s60.cpp9
-rw-r--r--src/gui/text/qfontdatabase_x11.cpp17
-rw-r--r--src/gui/text/qfontengine.cpp15
-rw-r--r--src/gui/text/qfontengine_ft.cpp2
-rw-r--r--src/gui/text/qfontengine_mac.mm102
-rw-r--r--src/gui/text/qfontengine_p.h3
-rw-r--r--src/gui/text/qfontengine_s60.cpp30
-rw-r--r--src/gui/text/qfontengine_s60_p.h2
-rw-r--r--src/gui/text/qfontengine_win.cpp31
-rw-r--r--src/gui/text/qfontengine_win_p.h4
-rw-r--r--src/gui/text/qfontmetrics.cpp27
-rw-r--r--src/gui/text/qstatictext.cpp178
-rw-r--r--src/gui/text/qstatictext.h8
-rw-r--r--src/gui/text/qstatictext_p.h13
-rw-r--r--src/gui/text/qtextcontrol.cpp10
-rw-r--r--src/gui/text/qtextdocument.cpp2
-rw-r--r--src/gui/text/qtextdocument_p.cpp34
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp2
-rw-r--r--src/gui/text/qtextengine.cpp20
-rw-r--r--src/gui/text/qtextimagehandler.cpp2
-rw-r--r--src/gui/text/qtextlayout.cpp139
-rw-r--r--src/gui/text/qtextlayout.h1
27 files changed, 495 insertions, 203 deletions
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 938decda73..b3d25267ac 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -895,7 +895,7 @@ void ValueExtractor::borderValue(const Declaration &decl, int *width, QCss::Bord
BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
*width = lengthValueFromData(data.width, f);
*style = data.style;
- *color = brushFromData(data.color, pal);
+ *color = data.color.type != BrushData::Invalid ? brushFromData(data.color, pal) : QBrush(QColor());
return;
}
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 2c2ceb1b8b..ee31fa2464 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -73,7 +73,7 @@
#endif
#endif
#ifdef Q_OS_SYMBIAN
-#include "qt_s60_p.h"
+#include <private/qt_s60_p.h>
#endif
#ifdef Q_WS_LITE
#include <QtGui/qplatformscreen_lite.h>
@@ -1312,9 +1312,11 @@ QFont::StyleHint QFont::styleHint() const
\value PreferAntialias antialias if possible.
\value OpenGLCompatible forces the use of OpenGL compatible
fonts.
- \value NoFontMerging If a font does not contain a character requested
- to draw then Qt automatically chooses a similar looking for that contains
- the character. This flag disables this feature.
+ \value NoFontMerging If the font selected for a certain writing system
+ does not contain a character requested to draw, then Qt automatically chooses a similar
+ looking font that contains the character. The NoFontMerging flag disables this feature.
+ Please note that enabling this flag will not prevent Qt from automatically picking a
+ suitable font when the selected font does not support the writing system of the text.
Any of these may be OR-ed with one of these flags:
@@ -1323,6 +1325,8 @@ QFont::StyleHint QFont::styleHint() const
\value PreferQuality prefer the best quality font. The font matcher
will use the nearest standard point size that the font
supports.
+ \value ForceIntegerMetrics forces the use of integer values in font engines that support fractional
+ font metrics.
*/
/*!
@@ -2638,8 +2642,10 @@ void QFontCache::cleanup()
} QT_CATCH (const std::bad_alloc &) {
// no cache - just ignore
}
- if (cache && cache->hasLocalData())
+ if (cache && cache->hasLocalData()) {
+ cache->localData()->clear();
cache->setLocalData(0);
+ }
}
#endif // QT_NO_THREAD
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index d71828d366..01892810a0 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -76,17 +76,18 @@ public:
};
enum StyleStrategy {
- PreferDefault = 0x0001,
- PreferBitmap = 0x0002,
- PreferDevice = 0x0004,
- PreferOutline = 0x0008,
- ForceOutline = 0x0010,
- PreferMatch = 0x0020,
- PreferQuality = 0x0040,
- PreferAntialias = 0x0080,
- NoAntialias = 0x0100,
- OpenGLCompatible = 0x0200,
- NoFontMerging = 0x8000
+ PreferDefault = 0x0001,
+ PreferBitmap = 0x0002,
+ PreferDevice = 0x0004,
+ PreferOutline = 0x0008,
+ ForceOutline = 0x0010,
+ PreferMatch = 0x0020,
+ PreferQuality = 0x0040,
+ PreferAntialias = 0x0080,
+ NoAntialias = 0x0100,
+ OpenGLCompatible = 0x0200,
+ ForceIntegerMetrics = 0x0400,
+ NoFontMerging = 0x8000
};
enum Weight {
diff --git a/src/gui/text/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp
index 52c77d63ba..ccd17a2123 100644
--- a/src/gui/text/qfont_s60.cpp
+++ b/src/gui/text/qfont_s60.cpp
@@ -40,8 +40,8 @@
****************************************************************************/
#include "qfont.h"
-#include "qt_s60_p.h"
-#include "qpixmap_s60_p.h"
+#include <private/qt_s60_p.h>
+#include <private/qpixmap_s60_p.h>
#include "qmutex.h"
QT_BEGIN_NAMESPACE
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index bc5b48f720..fbade23287 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -83,7 +83,7 @@ QT_BEGIN_NAMESPACE
#define SMOOTH_SCALABLE 0xffff
-extern int qt_defaultDpiY(); // in qfont.cpp
+Q_GUI_EXPORT extern int qt_defaultDpiY(); // in qfont.cpp
bool qt_enable_test_font = false;
diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp
index 87a73df2a3..ef5e0c44b7 100644
--- a/src/gui/text/qfontdatabase_s60.cpp
+++ b/src/gui/text/qfontdatabase_s60.cpp
@@ -45,8 +45,8 @@
#include "qfontengine_s60_p.h"
#include "qabstractfileengine.h"
#include "qdesktopservices.h"
-#include "qpixmap_s60_p.h"
-#include "qt_s60_p.h"
+#include <private/qpixmap_s60_p.h>
+#include <private/qt_s60_p.h>
#include "qendian.h"
#include <private/qcore_symbian_p.h>
#if defined(QT_NO_FREETYPE)
@@ -332,6 +332,11 @@ bool QFontDatabase::removeApplicationFont(int handle)
return false;
}
+bool QFontDatabase::removeAllApplicationFonts()
+{
+ return false;
+}
+
bool QFontDatabase::supportsThreadedFontRendering()
{
return false;
diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp
index bb1e60db77..3b2e4e9c4c 100644
--- a/src/gui/text/qfontdatabase_x11.cpp
+++ b/src/gui/text/qfontdatabase_x11.cpp
@@ -41,9 +41,9 @@
#include <qplatformdefs.h>
-#include <qdatetime.h>
#include <qdebug.h>
#include <qpaintdevice.h>
+#include <qelapsedtimer.h>
#include <private/qt_x11_p.h>
#include "qx11info_x11.h"
@@ -1218,7 +1218,7 @@ static void load(const QString &family = QString(), int script = -1, bool forceX
}
#ifdef QFONTDATABASE_DEBUG
- QTime t;
+ QElapsedTimer t;
t.start();
#endif
@@ -1301,7 +1301,7 @@ static void initializeDb()
if (!db || db->count)
return;
- QTime t;
+ QElapsedTimer t;
t.start();
#ifndef QT_NO_FONTCONFIG
@@ -1314,7 +1314,7 @@ static void initializeDb()
}
loadFontConfig();
- FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", t.elapsed());
+ FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", int(t.elapsed()));
#endif
t.start();
@@ -1939,8 +1939,13 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
fe = loadFc(d, script, req);
if (fe != 0 && fe->fontDef.pixelSize != req.pixelSize) {
- delete fe;
- fe = loadXlfd(d->screen, script, req);
+ QFontEngine *xlfdFontEngine = loadXlfd(d->screen, script, req);
+ if (xlfdFontEngine->fontDef.family == fe->fontDef.family) {
+ delete fe;
+ fe = xlfdFontEngine;
+ } else {
+ delete xlfdFontEngine;
+ }
}
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 40637492c7..060d9bc0ad 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -379,6 +379,15 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
Q_ASSERT(positions.size() == glyphs_out.size());
}
+void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
+{
+ glyph_metrics_t gi = boundingBox(glyph);
+ bool isValid = gi.isValid();
+ if (leftBearing != 0)
+ *leftBearing = isValid ? gi.x.toReal() : 0.0;
+ if (rightBearing != 0)
+ *rightBearing = isValid ? (gi.xoff - gi.x - gi.width).toReal() : 0.0;
+}
glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
{
@@ -1389,6 +1398,12 @@ glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
return overall;
}
+void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
+{
+ int which = highByte(glyph);
+ engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);
+}
+
void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
QPainterPath *path, QTextItem::RenderFlags flags)
{
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index a9def8e09b..449dffdc91 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -1368,7 +1368,7 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransfor
if (!gs) {
// don't try to load huge fonts
- bool draw_as_outline = fontDef.pixelSize * qSqrt(matrix.det()) >= 64;
+ bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
if (draw_as_outline)
return 0;
diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm
index 8588214b5c..0bfdbc04f3 100644
--- a/src/gui/text/qfontengine_mac.mm
+++ b/src/gui/text/qfontengine_mac.mm
@@ -53,6 +53,7 @@
#include <qvarlengtharray.h>
#include <qdebug.h>
#include <qendian.h>
+#include <qmath.h>
#include <ApplicationServices/ApplicationServices.h>
#include <AppKit/AppKit.h>
@@ -303,12 +304,20 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay
outGlyphs[idx] = tmpGlyphs[i] | fontIndex;
outAdvances_x[idx] = QFixed::fromReal(tmpPoints[i + 1].x - tmpPoints[i].x);
outAdvances_y[idx] = QFixed::fromReal(tmpPoints[i + 1].y - tmpPoints[i].y);
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ outAdvances_x[idx] = outAdvances_x[idx].round();
+ outAdvances_y[idx] = outAdvances_y[idx].round();
+ }
}
CGSize lastGlyphAdvance;
CTFontGetAdvancesForGlyphs(runFont, kCTFontHorizontalOrientation, tmpGlyphs + glyphCount - 1, &lastGlyphAdvance, 1);
outGlyphs[rtl ? 0 : (glyphCount - 1)] = tmpGlyphs[glyphCount - 1] | fontIndex;
- outAdvances_x[rtl ? 0 : (glyphCount - 1)] = QFixed::fromReal(lastGlyphAdvance.width);
+ outAdvances_x[rtl ? 0 : (glyphCount - 1)] =
+ (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? QFixed::fromReal(lastGlyphAdvance.width).round()
+ : QFixed::fromReal(lastGlyphAdvance.width);
}
outGlyphs += glyphCount;
outAttributes += glyphCount;
@@ -378,8 +387,11 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *
glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
{
QFixed w;
- for (int i = 0; i < glyphs.numGlyphs; ++i)
- w += glyphs.effectiveAdvance(i);
+ for (int i = 0; i < glyphs.numGlyphs; ++i) {
+ w += (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? glyphs.effectiveAdvance(i).round()
+ : glyphs.effectiveAdvance(i);
+ }
return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0);
}
glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
@@ -393,33 +405,51 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
ret.y = -QFixed::fromReal(rect.origin.y) - ret.height;
CGSize advances[1];
CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1);
- ret.xoff = QFixed::fromReal(advances[0].width).ceil();
- ret.yoff = QFixed::fromReal(advances[0].height).ceil();
+ ret.xoff = QFixed::fromReal(advances[0].width);
+ ret.yoff = QFixed::fromReal(advances[0].height);
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ ret.xoff = ret.xoff.round();
+ ret.yoff = ret.yoff.round();
+ }
+
return ret;
}
QFixed QCoreTextFontEngine::ascent() const
{
- return QFixed::fromReal(CTFontGetAscent(ctfont)).ceil();
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? QFixed::fromReal(CTFontGetAscent(ctfont)).round()
+ : QFixed::fromReal(CTFontGetAscent(ctfont));
}
QFixed QCoreTextFontEngine::descent() const
{
+ QFixed d = QFixed::fromReal(CTFontGetDescent(ctfont));
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ d = d.round();
+
// subtract a pixel to even out the historical +1 in QFontMetrics::height().
// Fix in Qt 5.
- return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil() - 1;
+ return d - 1;
}
QFixed QCoreTextFontEngine::leading() const
{
- return QFixed::fromReal(CTFontGetLeading(ctfont)).ceil();
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? QFixed::fromReal(CTFontGetLeading(ctfont)).round()
+ : QFixed::fromReal(CTFontGetLeading(ctfont));
}
QFixed QCoreTextFontEngine::xHeight() const
{
- return QFixed::fromReal(CTFontGetXHeight(ctfont)).ceil();
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round()
+ : QFixed::fromReal(CTFontGetXHeight(ctfont));
}
QFixed QCoreTextFontEngine::averageCharWidth() const
{
// ### Need to implement properly and get the information from the OS/2 Table.
- return QFontEngine::averageCharWidth();
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? QFontEngine::averageCharWidth().round()
+ : QFontEngine::averageCharWidth();
}
qreal QCoreTextFontEngine::maxCharWidth() const
@@ -787,6 +817,7 @@ struct QGlyphLayoutInfo
int *mappedFonts;
QTextEngine::ShaperFlags flags;
QFontEngineMacMulti::ShaperItem *shaperItem;
+ unsigned int styleStrategy;
};
static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATSULineRef lineRef, URefCon refCon,
@@ -856,6 +887,11 @@ static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATS
QFixed yAdvance = FixedToQFixed(baselineDeltas[glyphIdx]);
QFixed xAdvance = FixedToQFixed(layoutData[glyphIdx + 1].realPos - layoutData[glyphIdx].realPos);
+ if (nfo->styleStrategy & QFont::ForceIntegerMetrics) {
+ yAdvance = yAdvance.round();
+ xAdvance = xAdvance.round();
+ }
+
if (glyphId != 0xffff || i == 0) {
if (i < nfo->glyphs->numGlyphs)
{
@@ -1032,6 +1068,7 @@ bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyph
nfo.callbackCalled = false;
nfo.flags = flags;
nfo.shaperItem = shaperItem;
+ nfo.styleStrategy = fontDef.styleStrategy;
int prevNumGlyphs = *nglyphs;
@@ -1061,8 +1098,6 @@ bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyph
| kATSLineDisableAllJustification
;
- layopts |= kATSLineUseDeviceMetrics;
-
if (fontDef.styleStrategy & QFont::NoAntialias)
layopts |= kATSLineNoAntiAliasing;
@@ -1366,14 +1401,22 @@ void QFontEngineMac::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFla
for (int i = 0; i < glyphs->numGlyphs; ++i) {
glyphs->advances_x[i] = QFixed::fromReal(metrics[i].deviceAdvance.x);
glyphs->advances_y[i] = QFixed::fromReal(metrics[i].deviceAdvance.y);
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ glyphs->advances_y[i] = glyphs->advances_y[i].round();
+ }
}
}
glyph_metrics_t QFontEngineMac::boundingBox(const QGlyphLayout &glyphs)
{
QFixed w;
- for (int i = 0; i < glyphs.numGlyphs; ++i)
- w += glyphs.effectiveAdvance(i);
+ for (int i = 0; i < glyphs.numGlyphs; ++i) {
+ w += (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? glyphs.effectiveAdvance(i).round()
+ : glyphs.effectiveAdvance(i);
+ }
return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0);
}
@@ -1398,39 +1441,58 @@ glyph_metrics_t QFontEngineMac::boundingBox(glyph_t glyph)
gm.xoff = QFixed::fromReal(metrics.deviceAdvance.x);
gm.yoff = QFixed::fromReal(metrics.deviceAdvance.y);
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ gm.x = gm.x.floor();
+ gm.y = gm.y.floor();
+ gm.xoff = gm.xoff.round();
+ gm.yoff = gm.yoff.round();
+ }
+
return gm;
}
QFixed QFontEngineMac::ascent() const
{
- return m_ascent;
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? m_ascent.round()
+ : m_ascent;
}
QFixed QFontEngineMac::descent() const
{
// subtract a pixel to even out the historical +1 in QFontMetrics::height().
// Fix in Qt 5.
- return m_descent - 1;
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? m_descent.round() - 1
+ : m_descent;
}
QFixed QFontEngineMac::leading() const
{
- return m_leading;
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? m_leading.round()
+ : m_leading;
}
qreal QFontEngineMac::maxCharWidth() const
{
- return m_maxCharWidth;
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(m_maxCharWidth)
+ : m_maxCharWidth;
}
QFixed QFontEngineMac::xHeight() const
{
- return m_xHeight;
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? m_xHeight.round()
+ : m_xHeight;
}
QFixed QFontEngineMac::averageCharWidth() const
{
- return m_averageCharWidth;
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? m_averageCharWidth.round()
+ : m_averageCharWidth;
}
static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path)
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index d2114393fd..af116f742e 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -206,6 +206,8 @@ public:
virtual qreal minLeftBearing() const { return qreal(); }
virtual qreal minRightBearing() const { return qreal(); }
+ virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
+
virtual const char *name() const = 0;
virtual bool canRender(const QChar *string, int len) = 0;
@@ -374,6 +376,7 @@ public:
virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const;
virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const;
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags);
+ virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
virtual QFixed ascent() const;
virtual QFixed descent() const;
diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp
index 3ea084b525..c9ff661328 100644
--- a/src/gui/text/qfontengine_s60.cpp
+++ b/src/gui/text/qfontengine_s60.cpp
@@ -79,6 +79,31 @@ QByteArray QFontEngineS60Extensions::getSfntTable(uint tag) const
return result;
}
+bool QFontEngineS60Extensions::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ if (!m_trueTypeExtension->HasTrueTypeTable(tag))
+ return false;
+
+ bool result = true;
+ TInt error = KErrNone;
+ TInt tableByteLength;
+ TAny *table =
+ q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength));
+
+ if (error != KErrNone) {
+ return false;
+ } else if (*length > 0 && *length < tableByteLength) {
+ result = false; // Caller did not allocate enough memory
+ } else {
+ *length = tableByteLength;
+ if (buffer)
+ qMemCopy(buffer, table, tableByteLength);
+ }
+
+ m_trueTypeExtension->ReleaseTrueTypeTable(table);
+ return result;
+}
+
const unsigned char *QFontEngineS60Extensions::cmap() const
{
if (!m_cmap) {
@@ -326,6 +351,11 @@ QByteArray QFontEngineS60::getSfntTable(uint tag) const
return m_extensions->getSfntTable(tag);
}
+bool QFontEngineS60::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ return m_extensions->getSfntTableData(tag, buffer, length);
+}
+
QFontEngine::Type QFontEngineS60::type() const
{
return QFontEngine::S60FontEngine;
diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h
index 5834cc441d..a80af4d9a5 100644
--- a/src/gui/text/qfontengine_s60_p.h
+++ b/src/gui/text/qfontengine_s60_p.h
@@ -69,6 +69,7 @@ public:
QFontEngineS60Extensions(CFont* fontOwner, COpenFont *font);
QByteArray getSfntTable(uint tag) const;
+ bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
const unsigned char *cmap() const;
QPainterPath glyphOutline(glyph_t glyph) const;
CFont *fontOwner() const;
@@ -106,6 +107,7 @@ public:
qreal minRightBearing() const { return 0; }
QByteArray getSfntTable(uint tag) const;
+ bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
static qreal pixelsToPoints(qreal pixels, Qt::Orientation orientation = Qt::Horizontal);
static qreal pointsToPixels(qreal points, Qt::Orientation orientation = Qt::Horizontal);
diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp
index 55e93bd3c2..a805612ac4 100644
--- a/src/gui/text/qfontengine_win.cpp
+++ b/src/gui/text/qfontengine_win.cpp
@@ -39,6 +39,11 @@
**
****************************************************************************/
+#if _WIN32_WINNT < 0x0500
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
#include "qfontengine_p.h"
#include "qtextengine_p.h"
#include <qglobal.h>
@@ -649,6 +654,32 @@ static const ushort char_table[] = {
static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
+#ifndef Q_CC_MINGW
+void QFontEngineWin::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
+{
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+
+#ifndef Q_WS_WINCE
+ if (ttf)
+#endif
+
+ {
+ ABC abcWidths;
+ GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
+ if (leftBearing)
+ *leftBearing = abcWidths.abcA;
+ if (rightBearing)
+ *rightBearing = abcWidths.abcC;
+ }
+
+#ifndef Q_WS_WINCE
+ else {
+ QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
+ }
+#endif
+}
+#endif // Q_CC_MINGW
qreal QFontEngineWin::minLeftBearing() const
{
diff --git a/src/gui/text/qfontengine_win_p.h b/src/gui/text/qfontengine_win_p.h
index f9d8f8b768..68b53b5235 100644
--- a/src/gui/text/qfontengine_win_p.h
+++ b/src/gui/text/qfontengine_win_p.h
@@ -106,6 +106,10 @@ public:
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform);
virtual QImage alphaRGBMapForGlyph(glyph_t t, int margin, const QTransform &xform);
+#ifndef Q_CC_MINGW
+ virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
+#endif
+
int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const;
void getCMap();
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 13a5704573..5163c94727 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -63,7 +63,7 @@ extern void qt_format_text(const QFont& font, const QRectF &_r,
int tf, const QString &text, QRectF *brect,
int tabStops, int *tabArray, int tabArrayLen,
QPainter *painter);
-extern int qt_defaultDpi();
+Q_GUI_EXPORT extern int qt_defaultDpi();
/*****************************************************************************
QFontMetrics member functions
@@ -328,7 +328,7 @@ int QFontMetrics::height() const
{
QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
Q_ASSERT(engine != 0);
- return qRound(engine->ascent() + engine->descent()) + 1;
+ return qRound(engine->ascent()) + qRound(engine->descent()) + 1;
}
/*!
@@ -356,7 +356,7 @@ int QFontMetrics::lineSpacing() const
{
QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
Q_ASSERT(engine != 0);
- return qRound(engine->leading() + engine->ascent() + engine->descent()) + 1;
+ return qRound(engine->leading()) + qRound(engine->ascent()) + qRound(engine->descent()) + 1;
}
/*!
@@ -472,8 +472,9 @@ int QFontMetrics::leftBearing(QChar ch) const
int nglyphs = 9;
engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
// ### can nglyphs != 1 happen at all? Not currently I think
- glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]);
- return qRound(gi.x);
+ qreal lb;
+ engine->getGlyphBearings(glyphs.glyphs[0], &lb);
+ return qRound(lb);
}
/*!
@@ -506,8 +507,9 @@ int QFontMetrics::rightBearing(QChar ch) const
int nglyphs = 9;
engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
// ### can nglyphs != 1 happen at all? Not currently I think
- glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]);
- return qRound(gi.xoff - gi.x - gi.width);
+ qreal rb;
+ engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb);
+ return qRound(rb);
}
/*!
@@ -1317,8 +1319,9 @@ qreal QFontMetricsF::leftBearing(QChar ch) const
int nglyphs = 9;
engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
// ### can nglyphs != 1 happen at all? Not currently I think
- glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]);
- return gi.x.toReal();
+ qreal lb;
+ engine->getGlyphBearings(glyphs.glyphs[0], &lb);
+ return lb;
}
/*!
@@ -1351,8 +1354,10 @@ qreal QFontMetricsF::rightBearing(QChar ch) const
int nglyphs = 9;
engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
// ### can nglyphs != 1 happen at all? Not currently I think
- glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]);
- return (gi.xoff - gi.x - gi.width).toReal();
+ qreal rb;
+ engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb);
+ return rb;
+
}
/*!
diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp
index 1fabf12395..c7817c6e59 100644
--- a/src/gui/text/qstatictext.cpp
+++ b/src/gui/text/qstatictext.cpp
@@ -99,20 +99,27 @@ QT_BEGIN_NAMESPACE
point with no boundaries, and also when QPainter::drawText() is called with a bounding
rectangle.
- If a bounding rectangle is not required, create a QStaticText object without setting a maximum
- size. The text will then occupy a single line.
+ If a bounding rectangle is not required, create a QStaticText object without setting a preferred
+ text width. The text will then occupy a single line.
- If you set a maximum size on the QStaticText object, this will bound the text. The text will
- be formatted so that no line exceeds the given width. When the object is painted, it will
- be clipped at the given size. The position of the text is decided by the argument
- passed to QPainter::drawStaticText() and can change from call to call with a minimal impact
- on performance.
+ If you set a text width on the QStaticText object, this will bound the text. The text will
+ be formatted so that no line exceeds the given width. The text width set for QStaticText will
+ not automatically be used for clipping. To achieve clipping in addition to line breaks, use
+ QPainter::setClipRect(). The position of the text is decided by the argument passed to
+ QPainter::drawStaticText() and can change from call to call with a minimal impact on
+ performance.
QStaticText will attempt to guess the format of the input text using Qt::mightBeRichText().
To force QStaticText to display its contents as either plain text or rich text, use the
function QStaticText::setTextFormat() and pass in, respectively, Qt::PlainText and
Qt::RichText.
+ If it's the first time the static text is drawn, or if the static text, or the painter's font
+ or matrix have been altered since the last time it was drawn, the text's layout has to be
+ recalculated. This will impose an overhead on the QPainter::drawStaticText() call where the
+ relayout occurs. To avoid this overhead in the paint event, you can call prepare() ahead of
+ time to ensure that the layout is calculated.
+
\sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument
*/
@@ -143,12 +150,11 @@ QStaticText::QStaticText()
If an invalid size is passed for \a size the text will be unbounded.
*/
-QStaticText::QStaticText(const QString &text, const QSizeF &size)
+QStaticText::QStaticText(const QString &text)
: data(new QStaticTextPrivate)
{
data->text = text;
- data->maximumSize = size;
- data->init();
+ data->invalidate();
}
/*!
@@ -177,17 +183,17 @@ void QStaticText::detach()
}
/*!
- Prepares the QStaticText object for being painted with the given \a matrix and the given
- \a font to avoid overhead when the actual drawStaticText() call is made.
+ Prepares the QStaticText object for being painted with the given \a matrix and the given \a font
+ to avoid overhead when the actual drawStaticText() call is made.
- When drawStaticText() is called, the layout of the QStaticText will be recalculated if the
- painter's font or matrix is different from the one used for the currently cached layout. By
- default, QStaticText will use a default constructed QFont and an identity matrix to create
- its layout.
+ When drawStaticText() is called, the layout of the QStaticText will be recalculated if any part
+ of the QStaticText object has changed since the last time it was drawn. It will also be
+ recalculated if the painter's font or matrix are not the same as when the QStaticText was last
+ drawn.
- To avoid the overhead of creating the layout the first time you draw the QStaticText with
- a painter whose matrix or font are different from the defaults, you can use the prepare()
- function and pass in the matrix and font you expect to use when drawing the text.
+ To avoid the overhead of creating the layout the first time you draw the QStaticText after
+ making changes, you can use the prepare() function and pass in the \a matrix and \a font you
+ expect to use when drawing the text.
\sa QPainter::setFont(), QPainter::setMatrix()
*/
@@ -209,7 +215,7 @@ QStaticText &QStaticText::operator=(const QStaticText &other)
}
/*!
- Compares \a other to this QStaticText. Returns true if the texts, fonts and maximum sizes
+ Compares \a other to this QStaticText. Returns true if the texts, fonts and text widths
are equal.
*/
bool QStaticText::operator==(const QStaticText &other) const
@@ -217,7 +223,7 @@ bool QStaticText::operator==(const QStaticText &other) const
return (data == other.data
|| (data->text == other.data->text
&& data->font == other.data->font
- && data->maximumSize == other.data->maximumSize));
+ && data->textWidth == other.data->textWidth));
}
/*!
@@ -232,7 +238,7 @@ bool QStaticText::operator!=(const QStaticText &other) const
/*!
Sets the text of the QStaticText to \a text.
- \note This function will cause the layout of the text to be recalculated.
+ \note This function will cause the layout of the text to require recalculation.
\sa text()
*/
@@ -240,7 +246,7 @@ void QStaticText::setText(const QString &text)
{
detach();
data->text = text;
- data->init();
+ data->invalidate();
}
/*!
@@ -250,7 +256,7 @@ void QStaticText::setText(const QString &text)
displayed as is, whereas it will be interpreted as HTML if the format is Qt::RichText. HTML tags
that alter the font of the text, its color, or its layout are supported by QStaticText.
- \note This function will cause the layout of the text to be recalculated.
+ \note This function will cause the layout of the text to require recalculation.
\sa textFormat(), setText(), text()
*/
@@ -258,7 +264,7 @@ void QStaticText::setTextFormat(Qt::TextFormat textFormat)
{
detach();
data->textFormat = textFormat;
- data->init();
+ data->invalidate();
}
/*!
@@ -289,7 +295,7 @@ QString QStaticText::text() const
The default is QStaticText::ModerateCaching.
- \note This function will cause the layout of the text to be recalculated.
+ \note This function will cause the layout of the text to require recalculation.
\sa performanceHint()
*/
@@ -301,7 +307,7 @@ void QStaticText::setPerformanceHint(PerformanceHint performanceHint)
}
detach();
data->useBackendOptimizations = (performanceHint == AggressiveCaching);
- data->init();
+ data->invalidate();
}
/*!
@@ -315,48 +321,56 @@ QStaticText::PerformanceHint QStaticText::performanceHint() const
}
/*!
- Sets the maximum size of the QStaticText to \a size.
+ Sets the preferred width for this QStaticText. If the text is wider than the specified width,
+ it will be broken into multiple lines and grow vertically. If the text cannot be split into
+ multiple lines, it will be larger than the specified \a textWidth.
- \note This function will cause the layout of the text to be recalculated.
+ Setting the preferred text width to a negative number will cause the text to be unbounded.
- \sa maximumSize(), size()
+ Use size() to get the actual size of the text.
+
+ \note This function will cause the layout of the text to require recalculation.
+
+ \sa textWidth(), size()
*/
-void QStaticText::setMaximumSize(const QSizeF &size)
+void QStaticText::setTextWidth(qreal textWidth)
{
detach();
- data->maximumSize = size;
- data->init();
+ data->textWidth = textWidth;
+ data->invalidate();
}
/*!
- Returns the maximum size of the QStaticText.
+ Returns the preferred width for this QStaticText.
- \sa setMaximumSize()
+ \sa setTextWidth()
*/
-QSizeF QStaticText::maximumSize() const
+qreal QStaticText::textWidth() const
{
- return data->maximumSize;
+ return data->textWidth;
}
/*!
Returns the size of the bounding rect for this QStaticText.
- \sa maximumSize()
+ \sa textWidth()
*/
QSizeF QStaticText::size() const
{
+ if (data->needsRelayout)
+ data->init();
return data->actualSize;
}
QStaticTextPrivate::QStaticTextPrivate()
- : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false),
- useBackendOptimizations(false), textFormat(Qt::AutoText)
+ : textWidth(-1.0), items(0), itemCount(0), glyphPool(0), positionPool(0),
+ needsRelayout(true), useBackendOptimizations(false), textFormat(Qt::AutoText)
{
}
QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other)
- : text(other.text), font(other.font), maximumSize(other.maximumSize), matrix(other.matrix),
- items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false),
+ : text(other.text), font(other.font), textWidth(other.textWidth), matrix(other.matrix),
+ items(0), itemCount(0), glyphPool(0), positionPool(0), needsRelayout(true),
useBackendOptimizations(other.useBackendOptimizations), textFormat(other.textFormat)
{
}
@@ -373,8 +387,8 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q)
return q->data.data();
}
-extern int qt_defaultDpiX();
-extern int qt_defaultDpiY();
+Q_GUI_EXPORT extern int qt_defaultDpiX();
+Q_GUI_EXPORT extern int qt_defaultDpiY();
namespace {
@@ -388,8 +402,15 @@ namespace {
m_expectedItemCount(expectedItemCount),
m_expectedGlyphCount(expectedGlyphCount),
m_glyphPool(glyphPool),
- m_positionPool(positionPool)
+ m_positionPool(positionPool),
+ m_dirtyPen(false)
+ {
+ }
+
+ virtual void updateState(const QPaintEngineState &newState)
{
+ if (newState.state() & QPaintEngine::DirtyPen)
+ m_dirtyPen = true;
}
virtual void drawTextItem(const QPointF &position, const QTextItem &textItem)
@@ -412,7 +433,8 @@ namespace {
currentItem->numGlyphs = ti.glyphs.numGlyphs;
currentItem->glyphs = m_glyphPool;
currentItem->glyphPositions = m_positionPool;
- currentItem->color = state->pen().color();
+ if (m_dirtyPen)
+ currentItem->color = state->pen().color();
QTransform matrix = state->transform();
matrix.translate(position.x(), position.y());
@@ -435,7 +457,6 @@ namespace {
virtual bool begin(QPaintDevice *) { return true; }
virtual bool end() { return true; }
- virtual void updateState(const QPaintEngineState &) {}
virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
virtual Type type() const
{
@@ -461,6 +482,8 @@ namespace {
glyph_t *m_glyphPool;
QFixedPoint *m_positionPool;
+
+ bool m_dirtyPen;
};
class DrawTextItemDevice: public QPaintDevice
@@ -530,41 +553,61 @@ namespace {
};
}
-void QStaticTextPrivate::paintText(const QPointF &pos, QPainter *p)
+void QStaticTextPrivate::paintText(const QPointF &topLeftPosition, QPainter *p)
{
bool preferRichText = textFormat == Qt::RichText
|| (textFormat == Qt::AutoText && Qt::mightBeRichText(text));
if (!preferRichText) {
- if (maximumSize.isValid()) {
- QRectF boundingRect;
- p->drawText(QRectF(pos, maximumSize), Qt::TextWordWrap, text, &boundingRect);
-
- actualSize = boundingRect.size();
- needsClipRect = boundingRect.width() > maximumSize.width()
- || boundingRect.height() > maximumSize.height();
- } else {
- p->drawText(pos, text);
- needsClipRect = false;
-
- QFontMetrics fm(font);
- actualSize = fm.boundingRect(text).size();
+ QTextLayout textLayout;
+ textLayout.setText(text);
+ textLayout.setFont(font);
+
+ qreal leading = QFontMetricsF(font).leading();
+ qreal height = -leading;
+
+ textLayout.beginLayout();
+ while (1) {
+ QTextLine line = textLayout.createLine();
+ if (!line.isValid())
+ break;
+
+ if (textWidth >= 0.0)
+ line.setLineWidth(textWidth);
+ height += leading;
+ line.setPosition(QPointF(0.0, height));
+ height += line.height();
}
+ textLayout.endLayout();
+
+ actualSize = textLayout.boundingRect().size();
+ textLayout.draw(p, topLeftPosition);
} else {
QTextDocument document;
+#ifndef QT_NO_CSSPARSER
+ QColor color = p->pen().color();
+ document.setDefaultStyleSheet(QString::fromLatin1("body { color: #%1%2%3 }")
+ .arg(QString::number(color.red(), 16), 2, QLatin1Char('0'))
+ .arg(QString::number(color.green(), 16), 2, QLatin1Char('0'))
+ .arg(QString::number(color.blue(), 16), 2, QLatin1Char('0')));
+#endif
document.setDefaultFont(font);
+ document.setDocumentMargin(0.0);
+ if (textWidth >= 0.0)
+ document.setTextWidth(textWidth);
+#ifndef QT_NO_TEXTHTMLPARSER
document.setHtml(text);
+#else
+ document.setPlainText(text);
+#endif
- QRectF rect = maximumSize.isValid() ? QRectF(pos, maximumSize) : QRectF();
document.adjustSize();
p->save();
- p->translate(pos);
- document.drawContents(p, rect);
+ p->translate(topLeftPosition);
+ document.drawContents(p);
p->restore();
+
actualSize = document.size();
- needsClipRect = maximumSize.isValid()
- && (actualSize.width() > maximumSize.width()
- || actualSize.height() > maximumSize.height());
}
}
@@ -611,6 +654,7 @@ void QStaticTextPrivate::init()
paintText(QPointF(0, 0), &painter);
}
+ needsRelayout = false;
}
QT_END_NAMESPACE
diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h
index 00d42e0515..f3bef93f05 100644
--- a/src/gui/text/qstatictext.h
+++ b/src/gui/text/qstatictext.h
@@ -66,7 +66,7 @@ public:
};
QStaticText();
- QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF());
+ QStaticText(const QString &text);
QStaticText(const QStaticText &other);
~QStaticText();
@@ -76,12 +76,12 @@ public:
void setTextFormat(Qt::TextFormat textFormat);
Qt::TextFormat textFormat() const;
- void setMaximumSize(const QSizeF &maximumSize);
- QSizeF maximumSize() const;
+ void setTextWidth(qreal textWidth);
+ qreal textWidth() const;
QSizeF size() const;
- void prepare(const QTransform &matrix, const QFont &font);
+ void prepare(const QTransform &matrix = QTransform(), const QFont &font = QFont());
void setPerformanceHint(PerformanceHint performanceHint);
PerformanceHint performanceHint() const;
diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h
index e75824468b..f017ed1dcd 100644
--- a/src/gui/text/qstatictext_p.h
+++ b/src/gui/text/qstatictext_p.h
@@ -118,11 +118,16 @@ public:
void init();
void paintText(const QPointF &pos, QPainter *p);
+ void invalidate()
+ {
+ needsRelayout = true;
+ }
+
QAtomicInt ref; // 4 bytes per text
QString text; // 4 bytes per text
QFont font; // 8 bytes per text
- QSizeF maximumSize; // 16 bytes per text
+ qreal textWidth; // 8 bytes per text
QSizeF actualSize; // 16 bytes per text
QPointF position; // 16 bytes per text
@@ -132,11 +137,11 @@ public:
glyph_t *glyphPool; // 4 bytes per text
QFixedPoint *positionPool; // 4 bytes per text
- unsigned char needsClipRect : 1; // 1 byte per text
- unsigned char useBackendOptimizations : 1;
+ unsigned char needsRelayout : 1;
+ unsigned char useBackendOptimizations : 1; // 1 byte per text
unsigned char textFormat : 2;
// ================
- // 171 bytes per text
+ // 163 bytes per text
static QStaticTextPrivate *get(const QStaticText *q);
};
diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp
index 6864fe14aa..3c596e55ed 100644
--- a/src/gui/text/qtextcontrol.cpp
+++ b/src/gui/text/qtextcontrol.cpp
@@ -91,7 +91,7 @@
QT_BEGIN_NAMESPACE
#ifndef QT_NO_CONTEXTMENU
-#if defined(Q_WS_WIN)
+#if defined(Q_WS_WIN) || defined(Q_WS_X11)
extern bool qt_use_rtl_extensions;
#endif
#endif
@@ -1201,7 +1201,8 @@ void QTextControlPrivate::keyPressEvent(QKeyEvent *e)
blockFmt.setIndent(blockFmt.indent() - 1);
cursor.setBlockFormat(blockFmt);
} else {
- cursor.deletePreviousChar();
+ QTextCursor localCursor = cursor;
+ localCursor.deletePreviousChar();
}
goto accept;
}
@@ -1239,7 +1240,8 @@ void QTextControlPrivate::keyPressEvent(QKeyEvent *e)
}
#endif
else if (e == QKeySequence::Delete) {
- cursor.deleteChar();
+ QTextCursor localCursor = cursor;
+ localCursor.deleteChar();
}
else if (e == QKeySequence::DeleteEndOfWord) {
if (!cursor.hasSelection())
@@ -2080,7 +2082,7 @@ QMenu *QTextControl::createStandardContextMenu(const QPointF &pos, QWidget *pare
}
#endif
-#if defined(Q_WS_WIN)
+#if defined(Q_WS_WIN) || defined(Q_WS_X11)
if ((d->interactionFlags & Qt::TextEditable) && qt_use_rtl_extensions) {
#else
if (d->interactionFlags & Qt::TextEditable) {
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 9a1b70cb63..3e556a733e 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -1656,7 +1656,7 @@ static void printPage(int index, QPainter *painter, const QTextDocument *doc, co
painter->restore();
}
-extern int qt_defaultDpi();
+Q_GUI_EXPORT extern int qt_defaultDpi();
/*!
Prints the document to the given \a printer. The QPrinter must be
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 969d5b4632..e2bca04d8c 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
// The VxWorks DIAB compiler crashes when initializing the anonymouse union with { a7 }
#if !defined(Q_CC_DIAB)
# define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8) \
- QTextUndoCommand c = { a1, a2, 0, 0, a3, a4, a5, a6, { a7 }, a8 }
+ QTextUndoCommand c = { a1, a2, 0, 0, quint8(a3), a4, a5, a6, { a7 }, a8 }
#else
# define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8) \
QTextUndoCommand c = { a1, a2, 0, 0, a3, a4, a5, a6 }; c.blockFormat = a7; c.revision = a8
@@ -870,6 +870,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
undoEnabled = false;
beginEditBlock();
int editPos = -1;
+ int editLength = -1;
while (1) {
if (undo)
--undoState;
@@ -882,12 +883,16 @@ int QTextDocumentPrivate::undoRedo(bool undo)
PMDEBUG(" erase: from %d, length %d", c.pos, c.length);
c.command = QTextUndoCommand::Removed;
editPos = c.pos;
+ editLength = 0;
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;
+ if (editPos != (int)c.pos)
+ editLength = 0;
+ editPos = c.pos;
+ editLength += c.length;
break;
case QTextUndoCommand::BlockInserted:
case QTextUndoCommand::BlockAdded:
@@ -898,6 +903,7 @@ int QTextDocumentPrivate::undoRedo(bool undo)
else
c.command = QTextUndoCommand::BlockDeleted;
editPos = c.pos;
+ editLength = 0;
break;
case QTextUndoCommand::BlockRemoved:
case QTextUndoCommand::BlockDeleted:
@@ -908,7 +914,10 @@ int QTextDocumentPrivate::undoRedo(bool undo)
c.command = QTextUndoCommand::BlockInserted;
else
c.command = QTextUndoCommand::BlockAdded;
- editPos = c.pos + 1;
+ if (editPos != (int)c.pos)
+ editLength = 0;
+ editPos = c.pos;
+ editLength += 1;
break;
case QTextUndoCommand::CharFormatChanged: {
resetBlockRevision = -1; // ## TODO
@@ -919,7 +928,10 @@ 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;
+ if (editPos != (int)c.pos)
+ editLength = 0;
+ editPos = c.pos;
+ editLength += c.length;
break;
}
case QTextUndoCommand::BlockFormatChanged: {
@@ -987,13 +999,19 @@ int QTextDocumentPrivate::undoRedo(bool undo)
break;
}
undoEnabled = true;
- if (editPos < 0 && docChangeFrom >= 0) {
- editPos = qMin(docChangeFrom + docChangeLength, length() - 1);
- }
+
+ int newCursorPos = -1;
+
+ if (editPos >=0)
+ newCursorPos = editPos + editLength;
+ else if (docChangeFrom >= 0)
+ newCursorPos= qMin(docChangeFrom + docChangeLength, length() - 1);
+
endEditBlock();
emitUndoAvailable(isUndoAvailable());
emitRedoAvailable(isRedoAvailable());
- return editPos;
+
+ return newCursorPos;
}
/*!
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index b45fcbb9b8..f12bf0b2f5 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -75,7 +75,7 @@
QT_BEGIN_NAMESPACE
-extern int qt_defaultDpi();
+Q_GUI_EXPORT extern int qt_defaultDpi();
// ################ should probably add frameFormatChange notification!
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index b8265889da..d34553f13e 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -856,7 +856,7 @@ void QTextEngine::shapeLine(const QScriptLine &line)
}
}
-extern int qt_defaultDpiY(); // in qfont.cpp
+Q_GUI_EXPORT extern int qt_defaultDpiY(); // in qfont.cpp
void QTextEngine::shapeText(int item) const
{
@@ -1124,14 +1124,13 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
bool kerningEnabled = this->font(si).d->kerning;
HB_ShaperItem entire_shaper_item;
- entire_shaper_item.kerning_applied = false;
+ qMemSet(&entire_shaper_item, 0, sizeof(entire_shaper_item));
entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData());
entire_shaper_item.stringLength = layoutData->string.length();
entire_shaper_item.item.script = (HB_Script)si.analysis.script;
entire_shaper_item.item.pos = si.position;
entire_shaper_item.item.length = length(item);
entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;
- entire_shaper_item.glyphIndicesPresent = false;
HB_UChar16 upperCased[256]; // XXX what about making this 4096, so we don't have to extend it ever.
if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
@@ -1299,10 +1298,10 @@ QTextEngine::QTextEngine()
}
QTextEngine::QTextEngine(const QString &str, const QFont &f)
- : fnt(f)
+ : text(str),
+ fnt(f)
{
init(this);
- text = str;
}
QTextEngine::~QTextEngine()
@@ -1648,7 +1647,7 @@ glyph_metrics_t QTextEngine::boundingBox(int from, int len) const
}
}
- glyph_t glyph = glyphs.glyphs[logClusters[pos + ilen - 1]];
+ glyph_t glyph = glyphs.glyphs[logClusters[ilen - 1]];
glyph_metrics_t gi = fe->boundingBox(glyph);
if (gi.isValid())
gm.width -= qRound(gi.xoff - gi.x - gi.width);
@@ -2467,7 +2466,7 @@ void QTextEngine::splitItem(int item, int pos) const
if (pos <= 0)
return;
- layoutData->items.insert(item + 1, QScriptItem(layoutData->items[item]));
+ layoutData->items.insert(item + 1, layoutData->items[item]);
QScriptItem &oldItem = layoutData->items[item];
QScriptItem &newItem = layoutData->items[item+1];
newItem.position += pos;
@@ -2495,7 +2494,7 @@ void QTextEngine::splitItem(int item, int pos) const
// qDebug("split at position %d itempos=%d", pos, item);
}
-extern int qt_defaultDpiY();
+Q_GUI_EXPORT extern int qt_defaultDpiY();
QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
{
@@ -2610,10 +2609,9 @@ void QTextEngine::resolveAdditionalFormats() const
}
QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)
- : _layoutData(string, _memory, MemSize)
+ : QTextEngine(string, f),
+ _layoutData(string, _memory, MemSize)
{
- fnt = f;
- text = string;
stackEngine = true;
layoutData = &_layoutData;
}
diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp
index fa49a32954..6733793de5 100644
--- a/src/gui/text/qtextimagehandler.cpp
+++ b/src/gui/text/qtextimagehandler.cpp
@@ -123,7 +123,7 @@ static QSize getPixmapSize(QTextDocument *doc, const QTextImageFormat &format)
qreal scale = 1.0;
QPaintDevice *pdev = doc->documentLayout()->paintDevice();
if (pdev) {
- extern int qt_defaultDpi();
+ Q_GUI_EXPORT extern int qt_defaultDpi();
if (pm.isNull())
pm = getPixmap(doc, format);
if (!pm.isNull())
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index cc6793d759..ce7915d8e9 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -305,7 +305,7 @@ Qt::LayoutDirection QTextInlineObject::textDirection() const
Once the layout is done, these lines can be drawn on a paint
device.
- Here's some pseudo code that presents the layout phase:
+ Here's some code snippet that presents the layout phase:
\snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 0
The text can be drawn by calling the layout's draw() function:
@@ -1570,6 +1570,20 @@ qreal QTextLine::naturalTextWidth() const
return eng->lines[i].textWidth.toReal();
}
+/*! \since 4.7
+ Returns the horizontal advance of the text. The advance of the text
+ is the distance from its position to the next position at which
+ text would naturally be drawn.
+
+ By adding the advance to the position of the text line and using this
+ as the position of a second text line, you will be able to position
+ the two lines side-by-side without gaps in-between.
+*/
+qreal QTextLine::horizontalAdvance() const
+{
+ return eng->lines[i].textAdvance.toReal();
+}
+
/*!
Lays out the line with the given \a width. The line is filled from
its starting position with as many characters as will fit into
@@ -1644,28 +1658,67 @@ namespace {
struct LineBreakHelper
{
- LineBreakHelper() : glyphCount(0), maxGlyphs(0), manualWrap(false) {}
+ LineBreakHelper()
+ : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
+ manualWrap(false)
+ {
+ }
+
QScriptLine tmpData;
QScriptLine spaceData;
+ QGlyphLayout glyphs;
+
int glyphCount;
int maxGlyphs;
+ int currentPosition;
QFixed minw;
QFixed softHyphenWidth;
QFixed rightBearing;
+ QFixed minimumRightBearing;
+
+ QFontEngine *fontEngine;
+ const unsigned short *logClusters;
bool manualWrap;
bool checkFullOtherwiseExtend(QScriptLine &line);
+
+ QFixed calculateNewWidth(const QScriptLine &line) const {
+ return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth
+ - qMin(rightBearing, QFixed());
+ }
+
+ inline glyph_t currentGlyph() const
+ {
+ Q_ASSERT(currentPosition > 0);
+ return glyphs.glyphs[logClusters[currentPosition - 1]];
+ }
+
+ inline void adjustRightBearing()
+ {
+ if (currentPosition <= 0)
+ return;
+
+ qreal rb;
+ fontEngine->getGlyphBearings(currentGlyph(), 0, &rb);
+ rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
+ }
+
+ inline void resetRightBearing()
+ {
+ rightBearing = QFixed(1); // Any positive number is defined as invalid since only
+ // negative right bearings are interesting to us.
+ }
};
inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
{
LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
- QFixed newWidth = line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth + rightBearing;
+ QFixed newWidth = calculateNewWidth(line);
if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
return true;
@@ -1741,13 +1794,12 @@ void QTextLine::layout_helper(int maxGlyphs)
Qt::Alignment alignment = eng->option.alignment();
const HB_CharAttributes *attributes = eng->attributes();
- int pos = line.from;
+ lbh.currentPosition = line.from;
int end = 0;
- QGlyphLayout glyphs;
- const unsigned short *logClusters = eng->layoutData->logClustersPtr;
+ lbh.logClusters = eng->layoutData->logClustersPtr;
while (newItem < eng->layoutData->items.size()) {
- lbh.rightBearing = 0;
+ lbh.resetRightBearing();
lbh.softHyphenWidth = 0;
if (newItem != item) {
item = newItem;
@@ -1755,13 +1807,19 @@ void QTextLine::layout_helper(int maxGlyphs)
if (!current.num_glyphs) {
eng->shape(item);
attributes = eng->attributes();
- logClusters = eng->layoutData->logClustersPtr;
+ lbh.logClusters = eng->layoutData->logClustersPtr;
}
- pos = qMax(line.from, current.position);
+ lbh.currentPosition = qMax(line.from, current.position);
end = current.position + eng->length(item);
- glyphs = eng->shapedGlyphs(&current);
+ lbh.glyphs = eng->shapedGlyphs(&current);
}
const QScriptItem &current = eng->layoutData->items[item];
+ QFontEngine *fontEngine = eng->fontEngine(current);
+ if (lbh.fontEngine != fontEngine) {
+ lbh.fontEngine = fontEngine;
+ lbh.minimumRightBearing = qMin(QFixed(),
+ QFixed::fromReal(fontEngine->minRightBearing()));
+ }
lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
@@ -1791,8 +1849,8 @@ void QTextLine::layout_helper(int maxGlyphs)
if (!line.length && !lbh.tmpData.length)
line.setDefaultHeight(eng);
if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
- addNextCluster(pos, end, lbh.tmpData, lbh.glyphCount,
- current, logClusters, glyphs);
+ addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
+ current, lbh.logClusters, lbh.glyphs);
} else {
lbh.tmpData.length++;
}
@@ -1811,10 +1869,10 @@ void QTextLine::layout_helper(int maxGlyphs)
++lbh.glyphCount;
if (lbh.checkFullOtherwiseExtend(line))
goto found;
- } else if (attributes[pos].whiteSpace) {
- while (pos < end && attributes[pos].whiteSpace)
- addNextCluster(pos, end, lbh.spaceData, lbh.glyphCount,
- current, logClusters, glyphs);
+ } else if (attributes[lbh.currentPosition].whiteSpace) {
+ while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
+ addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
+ current, lbh.logClusters, lbh.glyphs);
if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line.
@@ -1823,19 +1881,19 @@ void QTextLine::layout_helper(int maxGlyphs)
} else {
bool sb_or_ws = false;
do {
- addNextCluster(pos, end, lbh.tmpData, lbh.glyphCount,
- current, logClusters, glyphs);
+ addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
+ current, lbh.logClusters, lbh.glyphs);
- if (attributes[pos].whiteSpace || attributes[pos-1].lineBreakType != HB_NoBreak) {
+ if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
sb_or_ws = true;
break;
- } else if (breakany && attributes[pos].charStop) {
+ } else if (breakany && attributes[lbh.currentPosition].charStop) {
break;
}
- } while (pos < end);
+ } while (lbh.currentPosition < end);
lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
- if (pos && attributes[pos - 1].lineBreakType == HB_SoftHyphen) {
+ if (lbh.currentPosition && attributes[lbh.currentPosition - 1].lineBreakType == HB_SoftHyphen) {
// if we are splitting up a word because of
// a soft hyphen then we ...
//
@@ -1853,43 +1911,40 @@ void QTextLine::layout_helper(int maxGlyphs)
// and thus become invisible again.
//
if (line.length)
- lbh.softHyphenWidth = glyphs.advances_x[logClusters[pos - 1]];
+ lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
else if (breakany)
- lbh.tmpData.textWidth += glyphs.advances_x[logClusters[pos - 1]];
+ lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
}
// The actual width of the text needs to take the right bearing into account. The
// right bearing is left-ward, which means that if the rightmost pixel is to the right
// of the advance of the glyph, the bearing will be negative. We flip the sign
// for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
- if (pos) {
- QFontEngine *fontEngine = eng->fontEngine(current);
- glyph_t glyph = glyphs.glyphs[logClusters[pos - 1]];
- glyph_metrics_t gi = fontEngine->boundingBox(glyph);
- if (gi.isValid())
- lbh.rightBearing = qMax(QFixed(), -(gi.xoff - gi.x - gi.width));
- }
+ // We ignore the right bearing if the minimum negative bearing is too little to
+ // expand the text beyond the edge.
+ if (sb_or_ws|breakany) {
+ if (lbh.calculateNewWidth(line) + lbh.minimumRightBearing > line.width)
+ lbh.adjustRightBearing();
+ if (lbh.checkFullOtherwiseExtend(line)) {
+ if (!breakany) {
+ line.textWidth += lbh.softHyphenWidth;
+ }
- if ((sb_or_ws|breakany) && lbh.checkFullOtherwiseExtend(line)) {
- if (!breakany) {
- line.textWidth += lbh.softHyphenWidth;
+ goto found;
}
-
- line.textAdvance = line.textWidth;
- line.textWidth += lbh.rightBearing;
-
- goto found;
}
}
- if (pos == end)
+ if (lbh.currentPosition == end)
newItem = item + 1;
}
LB_DEBUG("reached end of line");
lbh.checkFullOtherwiseExtend(line);
+found:
+ if (lbh.rightBearing > 0) // If right bearing has not yet been adjusted
+ lbh.adjustRightBearing();
line.textAdvance = line.textWidth;
- line.textWidth += lbh.rightBearing;
+ line.textWidth -= qMin(QFixed(), lbh.rightBearing);
-found:
if (line.length == 0) {
LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",
lbh.tmpData.length, lbh.tmpData.textWidth.toReal(),
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
index edae7decde..8c93ed65b6 100644
--- a/src/gui/text/qtextlayout.h
+++ b/src/gui/text/qtextlayout.h
@@ -202,6 +202,7 @@ public:
bool leadingIncluded() const;
qreal naturalTextWidth() const;
+ qreal horizontalAdvance() const;
QRectF naturalTextRect() const;
enum Edge {