diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/image/qbmphandler.cpp | 6 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 7 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 3 | ||||
-rw-r--r-- | src/gui/kernel/qshortcutmap.cpp | 12 | ||||
-rw-r--r-- | src/gui/kernel/qshortcutmap_p.h | 4 | ||||
-rw-r--r-- | src/gui/opengl/qopenglshaderprogram.cpp | 17 | ||||
-rw-r--r-- | src/gui/painting/qimagescale.cpp | 5 | ||||
-rw-r--r-- | src/gui/painting/qrasterizer.cpp | 28 | ||||
-rw-r--r-- | src/gui/text/qfontengine.cpp | 212 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/qfontengine_qpf2.cpp | 10 | ||||
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 81 |
12 files changed, 267 insertions, 120 deletions
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index f124cede36..ef12b23caa 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -212,6 +212,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int int blue_scale = 0; int alpha_scale = 0; + if (!d->isSequential()) + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4 ? BMP_WIN : bi.biSize)); // goto start of colormap or masks + if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) return false; @@ -299,9 +302,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int image.setDotsPerMeterX(bi.biXPelsPerMeter); image.setDotsPerMeterY(bi.biYPelsPerMeter); - if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap - if (ncols > 0) { // read color table uchar rgb[4]; int rgb_len = t == BMP_OLD ? 3 : 4; diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index aea6fc133f..045e36323f 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4237,9 +4237,6 @@ QImage QImage::alphaChannel() const if (!d) return QImage(); - if (d->format == QImage::Format_Alpha8) - return *this; - int w = d->width; int h = d->height; @@ -4269,6 +4266,10 @@ QImage QImage::alphaChannel() const src_data += d->bytes_per_line; dest_data += image.d->bytes_per_line; } + } else if (d->format == Format_Alpha8) { + const uchar *src_data = d->data; + uchar *dest_data = image.d->data; + memcpy(dest_data, src_data, d->bytes_per_line * h); } else { QImage alpha32 = *this; bool canSkipConversion = (d->format == Format_ARGB32 || d->format == Format_ARGB32_Premultiplied); diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 5e2a5b86a4..d0aab734dd 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -449,8 +449,7 @@ static QWindowGeometrySpecification windowGeometrySpecification; \row \li Miscellaneous \li startingUp(), - closingDown(), - type(). + closingDown(). \endtable \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 0ff5c36119..3e267f2e0b 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -386,9 +386,7 @@ QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e) result = find(e); if (result == QKeySequence::NoMatch && (e->modifiers() & Qt::KeypadModifier)) { // Try to find a match without keypad modifier - QKeyEvent event = *e; - event.setModifiers(e->modifiers() & ~Qt::KeypadModifier); - result = find(&event); + result = find(e, Qt::KeypadModifier); } if (result == QKeySequence::NoMatch && e->modifiers() & Qt::ShiftModifier) { // If Shift + Key_Backtab, also try Shift + Qt::Key_Tab @@ -441,13 +439,13 @@ bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const which can be access through matches(). \sa matches */ -QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e) +QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifiers) { Q_D(QShortcutMap); if (!d->sequences.count()) return QKeySequence::NoMatch; - createNewSequences(e, d->newEntries); + createNewSequences(e, d->newEntries, ignoredModifiers); #if defined(DEBUG_QSHORTCUTMAP) qDebug() << "Possible shortcut key sequences:" << d->newEntries; #endif @@ -549,7 +547,7 @@ void QShortcutMap::clearSequence(QVector<QKeySequence> &ksl) Alters \a seq to the new sequence state, based on the current sequence state, and the new key event \a e. */ -void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl) +void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl, int ignoredModifiers) { Q_D(QShortcutMap); QList<int> possibleKeys = QKeyMapper::possibleKeys(e); @@ -579,7 +577,7 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl) curKsl.setKey(0, 2); curKsl.setKey(0, 3); } - curKsl.setKey(possibleKeys.at(pkNum), index); + curKsl.setKey(possibleKeys.at(pkNum) & ~ignoredModifiers, index); } } } diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index 242c021ca4..2376d27c78 100644 --- a/src/gui/kernel/qshortcutmap_p.h +++ b/src/gui/kernel/qshortcutmap_p.h @@ -88,10 +88,10 @@ private: QKeySequence::SequenceMatch state(); void dispatchEvent(QKeyEvent *e); - QKeySequence::SequenceMatch find(QKeyEvent *e); + QKeySequence::SequenceMatch find(QKeyEvent *e, int ignoredModifiers = 0); QKeySequence::SequenceMatch matches(const QKeySequence &seq1, const QKeySequence &seq2) const; QVector<const QShortcutEntry *> matches() const; - void createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl); + void createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl, int ignoredModifiers); void clearSequence(QVector<QKeySequence> &ksl); int translateModifiers(Qt::KeyboardModifiers modifiers); diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index 41d53be31e..9714aa4bec 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -525,7 +525,8 @@ bool QOpenGLShader::compileSourceCode(const char *source) // The precision qualifiers are useful on OpenGL/ES systems, // but usually not present on desktop systems. - const QSurfaceFormat currentSurfaceFormat = QOpenGLContext::currentContext()->format(); + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + const QSurfaceFormat currentSurfaceFormat = ctx->format(); QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(QOpenGLContext::currentContext()); if (currentSurfaceFormat.renderableType() == QSurfaceFormat::OpenGL || ctx_d->workaround_missingPrecisionQualifiers @@ -545,10 +546,16 @@ bool QOpenGLShader::compileSourceCode(const char *source) } #endif - // Append #line directive in order to compensate for text insertion - QByteArray lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8(); - sourceChunks.append(lineDirective.constData()); - sourceChunkLengths.append(GLint(lineDirective.length())); + QByteArray lineDirective; + // #line is rejected by some drivers: + // "2.1 Mesa 8.1-devel (git-48a3d4e)" or "MESA 2.1 Mesa 8.1-devel" + const char *version = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VERSION)); + if (!version || !strstr(version, "2.1 Mesa 8")) { + // Append #line directive in order to compensate for text insertion + lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8(); + sourceChunks.append(lineDirective.constData()); + sourceChunkLengths.append(GLint(lineDirective.length())); + } // Append rest of shader code sourceChunks.append(source + versionDirectivePosition.position); diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 7b6a71737d..33dccc5374 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -305,7 +305,10 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, for (int x = 0; x < dw; x++) { const unsigned int *pix = sptr + xpoints[x]; const int xap = xapoints[x]; - *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + if (xap > 0) + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + else + *dptr = pix[0]; dptr++; } } diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index 75bf31cde1..34d72bf493 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -863,8 +863,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, const Q16Dot16 iLeft = int(left); const Q16Dot16 iRight = int(right); const Q16Dot16 leftWidth = IntToQ16Dot16(iLeft + 1) - - FloatToQ16Dot16(left); - const Q16Dot16 rightWidth = FloatToQ16Dot16(right) + - qSafeFloatToQ16Dot16(left); + const Q16Dot16 rightWidth = qSafeFloatToQ16Dot16(right) - IntToQ16Dot16(iRight); Q16Dot16 coverage[3]; @@ -898,8 +898,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, const Q16Dot16 iTopFP = IntToQ16Dot16(int(pa.y())); const Q16Dot16 iBottomFP = IntToQ16Dot16(int(pb.y())); - const Q16Dot16 yPa = FloatToQ16Dot16(pa.y()); - const Q16Dot16 yPb = FloatToQ16Dot16(pb.y()); + const Q16Dot16 yPa = qSafeFloatToQ16Dot16(pa.y()); + const Q16Dot16 yPb = qSafeFloatToQ16Dot16(pb.y()); for (Q16Dot16 yFP = iTopFP; yFP <= iBottomFP; yFP += Q16Dot16Factor) { const Q16Dot16 rowHeight = qMin(yFP + Q16Dot16Factor, yPb) - qMax(yFP, yPa); @@ -983,16 +983,16 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, const Q16Dot16 iRightFP = IntToQ16Dot16(int(right.y())); const Q16Dot16 iBottomFP = IntToQ16Dot16(int(bottomBound)); - Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope); - Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope); + Q16Dot16 leftIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope); + Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope); Q16Dot16 leftIntersectBf = 0; Q16Dot16 rightIntersectBf = 0; if (iLeftFP < iTopFP) - leftIntersectBf = FloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope); + leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope); if (iRightFP < iTopFP) - rightIntersectBf = FloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope); + rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope); Q16Dot16 rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom; Q16Dot16 topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf; @@ -1000,10 +1000,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, int leftMin, leftMax, rightMin, rightMax; - const Q16Dot16 yTopFP = FloatToQ16Dot16(top.y()); - const Q16Dot16 yLeftFP = FloatToQ16Dot16(left.y()); - const Q16Dot16 yRightFP = FloatToQ16Dot16(right.y()); - const Q16Dot16 yBottomFP = FloatToQ16Dot16(bottom.y()); + const Q16Dot16 yTopFP = qSafeFloatToQ16Dot16(top.y()); + const Q16Dot16 yLeftFP = qSafeFloatToQ16Dot16(left.y()); + const Q16Dot16 yRightFP = qSafeFloatToQ16Dot16(right.y()); + const Q16Dot16 yBottomFP = qSafeFloatToQ16Dot16(bottom.y()); rowTop = qMax(iTopFP, yTopFP); topLeftIntersectAf = leftIntersectAf + @@ -1021,7 +1021,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (yFP == iLeftFP) { const int y = Q16Dot16ToInt(yFP); - leftIntersectBf = FloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope); + leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope); topLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowTopLeft - yFP); bottomLeftIntersectAf = leftIntersectAf + Q16Dot16Multiply(topLeftSlopeFP, rowBottomLeft - yFP); } else { @@ -1031,7 +1031,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (yFP == iRightFP) { const int y = Q16Dot16ToInt(yFP); - rightIntersectBf = FloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope); + rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope); topRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowTopRight - yFP); bottomRightIntersectAf = rightIntersectAf + Q16Dot16Multiply(topRightSlopeFP, rowBottomRight - yFP); } else { diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index f9d924d10a..2087bad9f6 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -74,6 +74,16 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr } } +template<typename T> +static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output) +{ + if (source + sizeof(T) > end) + return false; + + *output = qFromBigEndian<T>(source); + return true; +} + // Harfbuzz helper functions #ifdef QT_ENABLE_HARFBUZZ_NG @@ -1039,26 +1049,38 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) return; const uchar *table = reinterpret_cast<const uchar *>(tab.constData()); + const uchar *end = table + tab.size(); + + quint16 version; + if (!qSafeFromBigEndian(table, end, &version)) + return; - unsigned short version = qFromBigEndian<quint16>(table); if (version != 0) { // qDebug("wrong version"); return; } - unsigned short numTables = qFromBigEndian<quint16>(table + 2); + quint16 numTables; + if (!qSafeFromBigEndian(table + 2, end, &numTables)) + return; + { int offset = 4; for(int i = 0; i < numTables; ++i) { - if (offset + 6 > tab.size()) { -// qDebug("offset out of bounds"); - goto end; - } const uchar *header = table + offset; - ushort version = qFromBigEndian<quint16>(header); - ushort length = qFromBigEndian<quint16>(header+2); - ushort coverage = qFromBigEndian<quint16>(header+4); + quint16 version; + if (!qSafeFromBigEndian(header, end, &version)) + goto end; + + quint16 length; + if (!qSafeFromBigEndian(header + 2, end, &length)) + goto end; + + quint16 coverage; + if (!qSafeFromBigEndian(header + 4, end, &coverage)) + goto end; + // qDebug("subtable: version=%d, coverage=%x",version, coverage); if(version == 0 && coverage == 0x0001) { if (offset + length > tab.size()) { @@ -1067,7 +1089,10 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) } const uchar *data = table + offset + 6; - ushort nPairs = qFromBigEndian<quint16>(data); + quint16 nPairs; + if (!qSafeFromBigEndian(data, end, &nPairs)) + goto end; + if(nPairs * 6 + 8 > length - 6) { // qDebug("corrupt table!"); // corrupt table @@ -1077,8 +1102,21 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) int off = 8; for(int i = 0; i < nPairs; ++i) { QFontEngine::KernPair p; - p.left_right = (((uint)qFromBigEndian<quint16>(data+off)) << 16) + qFromBigEndian<quint16>(data+off+2); - p.adjust = QFixed(((int)(short)qFromBigEndian<quint16>(data+off+4))) / scalingFactor; + + quint16 tmp; + if (!qSafeFromBigEndian(data + off, end, &tmp)) + goto end; + + p.left_right = uint(tmp) << 16; + if (!qSafeFromBigEndian(data + off + 2, end, &tmp)) + goto end; + + p.left_right |= tmp; + + if (!qSafeFromBigEndian(data + off + 4, end, &tmp)) + goto end; + + p.adjust = QFixed(int(short(tmp))) / scalingFactor; kerning_pairs.append(p); off += 6; } @@ -1098,26 +1136,31 @@ int QFontEngine::glyphCount() const QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p')); if (maxpTable.size() < 6) return 0; - return qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(maxpTable.constData() + 4)); + + const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4); + const uchar *end = source + maxpTable.size(); + + quint16 count = 0; + qSafeFromBigEndian(source, end, &count); + return count; } const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize) { const uchar *header = table; - if (tableSize < 4) - return 0; - const uchar *endPtr = table + tableSize; // version check - if (qFromBigEndian<quint16>(header) != 0) + quint16 version; + if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0) return 0; - unsigned short numTables = qFromBigEndian<quint16>(header + 2); - const uchar *maps = table + 4; - if (maps + 8 * numTables > endPtr) + quint16 numTables; + if (!qSafeFromBigEndian(header + 2, endPtr, &numTables)) return 0; + const uchar *maps = table + 4; + enum { Invalid, AppleRoman, @@ -1132,8 +1175,14 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy int tableToUse = -1; int score = Invalid; for (int n = 0; n < numTables; ++n) { - const quint16 platformId = qFromBigEndian<quint16>(maps + 8 * n); - const quint16 platformSpecificId = qFromBigEndian<quint16>(maps + 8 * n + 2); + quint16 platformId; + if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId)) + return 0; + + quint16 platformSpecificId; + if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId)) + return 0; + switch (platformId) { case 0: // Unicode if (score < Unicode && @@ -1187,20 +1236,30 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy resolveTable: *isSymbolFont = (symbolTable > -1); - unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4); + quint32 unicode_table; + if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table)) + return 0; - if (!unicode_table || unicode_table + 8 > tableSize) + if (!unicode_table) return 0; // get the header of the unicode table header = table + unicode_table; - unsigned short format = qFromBigEndian<quint16>(header); - unsigned int length; - if(format < 8) - length = qFromBigEndian<quint16>(header + 2); - else - length = qFromBigEndian<quint32>(header + 4); + quint16 format; + if (!qSafeFromBigEndian(header, endPtr, &format)) + return 0; + + quint32 length; + if (format < 8) { + quint16 tmp; + if (!qSafeFromBigEndian(header + 2, endPtr, &tmp)) + return 0; + length = tmp; + } else { + if (!qSafeFromBigEndian(header + 4, endPtr, &length)) + return 0; + } if (table + unicode_table + length > endPtr) return 0; @@ -1215,7 +1274,7 @@ resolveTable: // Check that none of the latin1 range are in the unicode table bool unicodeTableHasLatin1 = false; for (int uc=0x00; uc<0x100; ++uc) { - if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) { + if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) { unicodeTableHasLatin1 = true; break; } @@ -1225,7 +1284,7 @@ resolveTable: bool unicodeTableHasSymbols = false; if (!unicodeTableHasLatin1) { for (int uc=0xf000; uc<0xf100; ++uc) { - if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) { + if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) { unicodeTableHasSymbols = true; break; } @@ -1243,12 +1302,17 @@ resolveTable: return table + unicode_table; } -quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) +quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode) { - unsigned short format = qFromBigEndian<quint16>(cmap); + const uchar *end = cmap + cmapSize; + quint16 format; + if (!qSafeFromBigEndian(cmap, end, &format)) + return 0; + if (format == 0) { - if (unicode < 256) - return (int) *(cmap+6+unicode); + const uchar *ptr = cmap + 6 + unicode; + if (unicode < 256 && ptr < end) + return quint32(*ptr); } else if (format == 4) { /* some fonts come with invalid cmap tables, where the last segment specified end = start = rangeoffset = 0xffff, delta = 0x0001 @@ -1257,25 +1321,49 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) */ if(unicode >= 0xffff) return 0; - quint16 segCountX2 = qFromBigEndian<quint16>(cmap + 6); + + quint16 segCountX2; + if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2)) + return 0; + const unsigned char *ends = cmap + 14; + int i = 0; - for (; i < segCountX2/2 && qFromBigEndian<quint16>(ends + 2*i) < unicode; i++) {} + for (; i < segCountX2/2; ++i) { + quint16 codePoint; + if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint)) + return 0; + if (codePoint >= unicode) + break; + } const unsigned char *idx = ends + segCountX2 + 2 + 2*i; - quint16 startIndex = qFromBigEndian<quint16>(idx); + quint16 startIndex; + if (!qSafeFromBigEndian(idx, end, &startIndex)) + return 0; if (startIndex > unicode) return 0; idx += segCountX2; - qint16 idDelta = (qint16)qFromBigEndian<quint16>(idx); + + quint16 tmp; + if (!qSafeFromBigEndian(idx, end, &tmp)) + return 0; + qint16 idDelta = qint16(tmp); + idx += segCountX2; - quint16 idRangeoffset_t = (quint16)qFromBigEndian<quint16>(idx); + + quint16 idRangeoffset_t; + if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t)) + return 0; quint16 glyphIndex; if (idRangeoffset_t) { - quint16 id = qFromBigEndian<quint16>(idRangeoffset_t + 2*(unicode - startIndex) + idx); + quint16 id; + if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id)) + return 0; + if (id) glyphIndex = (idDelta + id) % 0x10000; else @@ -1285,13 +1373,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) } return glyphIndex; } else if (format == 6) { - quint16 tableSize = qFromBigEndian<quint16>(cmap + 2); + quint16 tableSize; + if (!qSafeFromBigEndian(cmap + 2, end, &tableSize)) + return 0; - quint16 firstCode6 = qFromBigEndian<quint16>(cmap + 6); + quint16 firstCode6; + if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6)) + return 0; if (unicode < firstCode6) return 0; - quint16 entryCount6 = qFromBigEndian<quint16>(cmap + 8); + quint16 entryCount6; + if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6)) + return 0; if (entryCount6 * 2 + 10 > tableSize) return 0; @@ -1300,9 +1394,14 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) return 0; quint16 entryIndex6 = unicode - firstCode6; - return qFromBigEndian<quint16>(cmap + 10 + (entryIndex6 * 2)); + + quint16 index = 0; + qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index); + return index; } else if (format == 12) { - quint32 nGroups = qFromBigEndian<quint32>(cmap + 12); + quint32 nGroups; + if (!qSafeFromBigEndian(cmap + 12, end, &nGroups)) + return 0; cmap += 16; // move to start of groups @@ -1310,13 +1409,24 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) while (left <= right) { int middle = left + ( ( right - left ) >> 1 ); - quint32 startCharCode = qFromBigEndian<quint32>(cmap + 12*middle); + quint32 startCharCode; + if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode)) + return 0; + if(unicode < startCharCode) right = middle - 1; else { - quint32 endCharCode = qFromBigEndian<quint32>(cmap + 12*middle + 4); - if(unicode <= endCharCode) - return qFromBigEndian<quint32>(cmap + 12*middle + 8) + unicode - startCharCode; + quint32 endCharCode; + if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode)) + return 0; + + if (unicode <= endCharCode) { + quint32 index; + if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index)) + return 0; + + return index + unicode - startCharCode; + } left = middle + 1; } } diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 5329a5f11a..780104bc37 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -240,7 +240,7 @@ public: QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, 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); + static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode); static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily); diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index a678b4c8ea..f2e05631a3 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -322,9 +322,9 @@ bool QFontEngineQPF2::getSfntTableData(uint tag, uchar *buffer, uint *length) co glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const { - glyph_t glyph = getTrueTypeGlyphIndex(cmap, ucs4); + glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); if (glyph == 0 && symbol && ucs4 < 0x100) - glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); if (!findGlyph(glyph)) glyph = 0; @@ -348,16 +348,16 @@ bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyp QStringIterator it(str, str + len); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); ++glyph_pos; } } else { QStringIterator it(str, str + len); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index d56b9cf1b1..0c729c74d1 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1656,8 +1656,8 @@ namespace { bool checkFullOtherwiseExtend(QScriptLine &line); QFixed calculateNewWidth(const QScriptLine &line) const { - return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth - - qMin(rightBearing, QFixed()); + return line.textWidth + tmpData.textWidth + spaceData.textWidth + + softHyphenWidth + negativeRightBearing(); } inline glyph_t currentGlyph() const @@ -1677,33 +1677,51 @@ namespace { } } - inline void adjustRightBearing(glyph_t glyph) + inline void calculateRightBearing(glyph_t glyph) { qreal rb; fontEngine->getGlyphBearings(glyph, 0, &rb); - rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); + + // We only care about negative right bearings, so we limit the range + // of the bearing here so that we can assume it's negative in the rest + // of the code, as well ase use QFixed(1) as a sentinel to represent + // the state where we have yet to compute the right bearing. + rightBearing = qMin(QFixed::fromReal(rb), QFixed(0)); } - inline void adjustRightBearing() + inline void calculateRightBearing() { if (currentPosition <= 0) return; - adjustRightBearing(currentGlyph()); + calculateRightBearing(currentGlyph()); } - inline void adjustPreviousRightBearing() + inline void calculateRightBearingForPreviousGlyph() { if (previousGlyph > 0) - adjustRightBearing(previousGlyph); + calculateRightBearing(previousGlyph); } + static const QFixed RightBearingNotCalculated; + inline void resetRightBearing() { - rightBearing = QFixed(1); // Any positive number is defined as invalid since only - // negative right bearings are interesting to us. + rightBearing = RightBearingNotCalculated; + } + + // We express the negative right bearing as an absolute number + // so that it can be applied to the width using addition. + inline QFixed negativeRightBearing() const + { + if (rightBearing == RightBearingNotCalculated) + return QFixed(0); + + return qAbs(rightBearing); } }; +const QFixed LineBreakHelper::RightBearingNotCalculated = QFixed(1); + inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) { LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); @@ -1856,7 +1874,7 @@ void QTextLine::layout_helper(int maxGlyphs) current, lbh.logClusters, lbh.glyphs); } else { lbh.tmpData.length++; - lbh.adjustPreviousRightBearing(); + lbh.calculateRightBearingForPreviousGlyph(); } line += lbh.tmpData; goto found; @@ -1938,22 +1956,29 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.tmpData.textWidth += lbh.glyphs.advances[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. - // 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) { - QFixed rightBearing = lbh.rightBearing; // store previous right bearing + // To compute the final width of the text we need to take negative right bearing + // into account (negative right bearing means the glyph has pixel data past the + // advance length). Note that the negative right bearing is an absolute number, + // so that we can apply it to the width using straight forward addition. + + // Store previous right bearing (for the already accepted glyph) in case we + // end up breaking due to the current glyph being too wide. + QFixed previousRightBearing = lbh.rightBearing; + + // We ignore the right bearing if the minimum negative bearing is too little to + // expand the text beyond the edge. if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width) - lbh.adjustRightBearing(); + lbh.calculateRightBearing(); + if (lbh.checkFullOtherwiseExtend(line)) { - // we are too wide, fix right bearing - if (rightBearing <= 0) - lbh.rightBearing = rightBearing; // take from cache + // We are too wide to accept the next glyph with its bearing, so we restore the + // right bearing to that of the previous glyph (the one that was already accepted), + // so that the bearing can be be applied to the final width of the text below. + if (previousRightBearing != LineBreakHelper::RightBearingNotCalculated) + lbh.rightBearing = previousRightBearing; else - lbh.adjustPreviousRightBearing(); + lbh.calculateRightBearingForPreviousGlyph(); if (!breakany) { line.textWidth += lbh.softHyphenWidth; @@ -1970,10 +1995,14 @@ void QTextLine::layout_helper(int maxGlyphs) LB_DEBUG("reached end of line"); lbh.checkFullOtherwiseExtend(line); found: - if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted - lbh.adjustRightBearing(); line.textAdvance = line.textWidth; - line.textWidth -= qMin(QFixed(), lbh.rightBearing); + + // If right bearing has not been calculated yet, do that now + if (lbh.rightBearing == LineBreakHelper::RightBearingNotCalculated && !lbh.whiteSpaceOrObject) + lbh.calculateRightBearing(); + + // Then apply any negative right bearing + line.textWidth += lbh.negativeRightBearing(); if (line.length == 0) { LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", |