summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-03-18 04:27:25 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-03-18 04:27:25 (GMT)
commit4dd9931c91aed711a888fb108f9f7225fd3e8045 (patch)
tree8a577565d6ba4fab08d48dbd8b93845fdcc80bc6 /src/gui
parentd3c8da01258a963c80f888f4acee722a84618db3 (diff)
parent91b29b3b00ba9292cfcbeb2ac93c4b1f7bed2bd6 (diff)
downloadQt-4dd9931c91aed711a888fb108f9f7225fd3e8045.zip
Qt-4dd9931c91aed711a888fb108f9f7225fd3e8045.tar.gz
Qt-4dd9931c91aed711a888fb108f9f7225fd3e8045.tar.bz2
Merge branch '4.6' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.6-integration
* '4.6' of scm.dev.nokia.troll.no:qt/oslo-staging-2: Optimize getting bearings of a glyph on Windows for true type fonts Fixes blending problem when paiting non-opaque items with cache enabled. Optimize speed of QTextLayout and QPainter::drawText Fix a crash in animation groups when deleting uncontrolled animations
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp6
-rw-r--r--src/gui/text/qfontengine.cpp14
-rw-r--r--src/gui/text/qfontengine_p.h3
-rw-r--r--src/gui/text/qfontengine_win.cpp24
-rw-r--r--src/gui/text/qfontengine_win_p.h2
-rw-r--r--src/gui/text/qfontmetrics.cpp21
-rw-r--r--src/gui/text/qtextlayout.cpp122
7 files changed, 144 insertions, 48 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 4ee2301..6934abc 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -4285,6 +4285,12 @@ static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &
if (!subPix.isNull()) {
// Blit the subpixmap into the main pixmap.
pixmapPainter.begin(pix);
+ if (item->cacheMode() == QGraphicsItem::DeviceCoordinateCache
+ && itemToPixmap.type() > QTransform::TxTranslate) {
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
+ } else {
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ }
pixmapPainter.setClipRegion(pixmapExposed);
pixmapPainter.drawPixmap(br.topLeft(), subPix);
pixmapPainter.end();
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index c000457..3ec389f 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -379,6 +379,14 @@ 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);
+ if (leftBearing != 0)
+ *leftBearing = gi.x.toReal();
+ if (rightBearing != 0)
+ *rightBearing = (gi.xoff - gi.x - gi.width).toReal();
+}
glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
{
@@ -1385,6 +1393,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_p.h b/src/gui/text/qfontengine_p.h
index 71ab5a5..e645caf 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_win.cpp b/src/gui/text/qfontengine_win.cpp
index 1a815d3..a133b48 100644
--- a/src/gui/text/qfontengine_win.cpp
+++ b/src/gui/text/qfontengine_win.cpp
@@ -649,6 +649,30 @@ static const ushort char_table[] = {
static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
+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
+}
qreal QFontEngineWin::minLeftBearing() const
{
diff --git a/src/gui/text/qfontengine_win_p.h b/src/gui/text/qfontengine_win_p.h
index f9d8f8b..f19e48e 100644
--- a/src/gui/text/qfontengine_win_p.h
+++ b/src/gui/text/qfontengine_win_p.h
@@ -106,6 +106,8 @@ public:
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform);
virtual QImage alphaRGBMapForGlyph(glyph_t t, int margin, const QTransform &xform);
+ virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
+
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 41d0af1..44a18de 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -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/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index af91603..3c0e85e 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1644,28 +1644,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 +1780,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 +1793,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 +1835,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 +1855,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 +1867,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,41 +1897,39 @@ 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.textWidth += lbh.rightBearing;
-
- goto found;
}
}
- if (pos == end)
+ if (lbh.currentPosition == end)
newItem = item + 1;
}
LB_DEBUG("reached end of line");
lbh.checkFullOtherwiseExtend(line);
- line.textWidth += lbh.rightBearing;
-
found:
+ if (lbh.rightBearing > 0) // If right bearing has not yet been adjusted
+ lbh.adjustRightBearing();
+ line.textWidth -= qMin(QFixed(), lbh.rightBearing);
+
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(),