From 152e496cdac8529fea53ed1006851546203a60b7 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 13 Apr 2016 16:33:25 +0200 Subject: Avoid conversion warnings in qrgba64.h Make implicit down conversions explicit to silence the most pedantic of compiler warnings. Task-number: QTBUG-52545 Change-Id: Id8f9574b47c8b4ee43023c80a3e009fab0e85008 Reviewed-by: Friedemann Kleint --- src/gui/painting/qrgba64.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h index fab9506ff2..413315f12a 100644 --- a/src/gui/painting/qrgba64.h +++ b/src/gui/painting/qrgba64.h @@ -97,7 +97,7 @@ public: Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromArgb32(uint rgb) { - return fromRgba(rgb >> 16, rgb >> 8, rgb, rgb >> 24); + return fromRgba(quint8(rgb >> 16), quint8(rgb >> 8), quint8(rgb), quint8(rgb >> 24)); } Q_DECL_CONSTEXPR bool isOpaque() const @@ -109,10 +109,10 @@ public: return (rgba & alphaMask()) == 0; } - Q_DECL_CONSTEXPR quint16 red() const { return rgba >> RedShift; } - Q_DECL_CONSTEXPR quint16 green() const { return rgba >> GreenShift; } - Q_DECL_CONSTEXPR quint16 blue() const { return rgba >> BlueShift; } - Q_DECL_CONSTEXPR quint16 alpha() const { return rgba >> AlphaShift; } + Q_DECL_CONSTEXPR quint16 red() const { return quint16(rgba >> RedShift); } + Q_DECL_CONSTEXPR quint16 green() const { return quint16(rgba >> GreenShift); } + Q_DECL_CONSTEXPR quint16 blue() const { return quint16(rgba >> BlueShift); } + Q_DECL_CONSTEXPR quint16 alpha() const { return quint16(rgba >> AlphaShift); } void setRed(quint16 _red) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << RedShift)) | (quint64(_red) << RedShift); } void setGreen(quint16 _green) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << GreenShift)) | (quint64(_green) << GreenShift); } void setBlue(quint16 _blue) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << BlueShift)) | (quint64(_blue) << BlueShift); } @@ -124,11 +124,11 @@ public: Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(alpha()); } Q_DECL_CONSTEXPR uint toArgb32() const { - return (alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8(); + return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8()); } Q_DECL_CONSTEXPR ushort toRgb16() const { - return (red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11); + return ushort((red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11)); } Q_DECL_RELAXED_CONSTEXPR QRgba64 premultiplied() const @@ -137,7 +137,7 @@ public: const quint16 r = div_65535(red() * a); const quint16 g = div_65535(green() * a); const quint16 b = div_65535(blue() * a); - return fromRgba64(r, g, b, a); + return fromRgba64(r, g, b, quint16(a)); } Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied() const @@ -163,18 +163,18 @@ public: private: static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint64 alphaMask() { return Q_UINT64_C(0xffff) << AlphaShift; } - static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint div_257_floor(uint x) { return (x - (x >> 8)) >> 8; } - static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint div_257(uint x) { return div_257_floor(x + 128); } - static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } + static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint8 div_257_floor(uint x) { return quint8((x - (x >> 8)) >> 8); } + static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint8 div_257(quint16 x) { return div_257_floor(x + 128U); } + static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint16 div_65535(uint x) { return quint16((x + (x>>16) + 0x8000U) >> 16); } Q_DECL_RELAXED_CONSTEXPR Q_ALWAYS_INLINE QRgba64 unpremultiplied_32bit() const { if (isOpaque() || isTransparent()) return *this; const quint32 a = alpha(); - const quint16 r = (quint32(red()) * 0xffff + a/2) / a; - const quint16 g = (quint32(green()) * 0xffff + a/2) / a; - const quint16 b = (quint32(blue()) * 0xffff + a/2) / a; - return fromRgba64(r, g, b, a); + const quint16 r = quint16((red() * 0xffff + a/2) / a); + const quint16 g = quint16((green() * 0xffff + a/2) / a); + const quint16 b = quint16((blue() * 0xffff + a/2) / a); + return fromRgba64(r, g, b, quint16(a)); } Q_DECL_RELAXED_CONSTEXPR Q_ALWAYS_INLINE QRgba64 unpremultiplied_64bit() const { @@ -182,10 +182,10 @@ private: return *this; const quint64 a = alpha(); const quint64 fa = (Q_UINT64_C(0xffff00008000) + a/2) / a; - const quint16 r = (red() * fa + 0x80000000) >> 32; - const quint16 g = (green() * fa + 0x80000000) >> 32; - const quint16 b = (blue() * fa + 0x80000000) >> 32; - return fromRgba64(r, g, b, a); + const quint16 r = quint16((red() * fa + 0x80000000) >> 32); + const quint16 g = quint16((green() * fa + 0x80000000) >> 32); + const quint16 b = quint16((blue() * fa + 0x80000000) >> 32); + return fromRgba64(r, g, b, quint16(a)); } }; -- cgit v1.2.3 From 7094466f7d0c2176eb3080021a4ea5d220555df9 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 30 Mar 2016 13:15:02 +0200 Subject: Interpret fixed CSS line-height as minimum rather than absolute The QTextBlockFormat::FixedHeight overrides the line height regardless of its calculated height. If the line contains objects or text which is higher than the specified line height, using FixedHeight will cause them to overlap with the previous line. This is not what happens in normal web browsers. The expected behavior is that the line height given in CSS is the minimum height, but that we still reserve space needed to display everything without overlaps. To make it possible for people to retain the old behavior, we introduce the -qt-line-height-type property, which allows them to override the default. This also fixes output from toHtml() to use the new property rather than set the minimum height of the paragraph or the "line-spacing" property, which does not exist in either CSS nor in Qt. [ChangeLog][QtGui][Important Behavior Changes] When line height is specified in pixels, this is now interpreted as the minimum line height rather than an absolute line height to avoid overlaps. To get the old behavior, use the -qt-line-height-type property in CSS and set it to "fixed". Task-number: QTBUG-51962 Change-Id: Ic2dde649b69209672170dad4c2de1e1c432a1078 Reviewed-by: Lars Knoll --- src/gui/text/qcssparser.cpp | 1 + src/gui/text/qcssparser_p.h | 1 + src/gui/text/qtextdocument.cpp | 17 ++++++++-------- src/gui/text/qtexthtmlparser.cpp | 44 ++++++++++++++++++++++++++++++++-------- src/gui/text/qtexthtmlparser_p.h | 1 + 5 files changed, 47 insertions(+), 17 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index b9e05e726e..53d4e3fa36 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -67,6 +67,7 @@ struct QCssKnownValue static const QCssKnownValue properties[NumProperties - 1] = { { "-qt-background-role", QtBackgroundRole }, { "-qt-block-indent", QtBlockIndent }, + { "-qt-line-height-type", QtLineHeightType }, { "-qt-list-indent", QtListIndent }, { "-qt-list-number-prefix", QtListNumberPrefix }, { "-qt-list-number-suffix", QtListNumberSuffix }, diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index b7692d32aa..4da7b62dba 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -189,6 +189,7 @@ enum Property { QtListNumberPrefix, QtListNumberSuffix, LineHeight, + QtLineHeightType, NumProperties }; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index f50f771c07..febd5da488 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2763,26 +2763,25 @@ void QTextHtmlExporter::emitBlockAttributes(const QTextBlock &block) } if (format.lineHeightType() != QTextBlockFormat::SingleHeight) { + html += QLatin1String(" line-height:") + + QString::number(format.lineHeight()); switch (format.lineHeightType()) { case QTextBlockFormat::ProportionalHeight: + html += QLatin1String("%;"); + break; case QTextBlockFormat::FixedHeight: - html += QLatin1String(" line-height:"); + html += QLatin1String("; -qt-line-height-type: fixed;"); break; case QTextBlockFormat::MinimumHeight: - html += QLatin1String(" min-height:"); + html += QLatin1String("px;"); break; case QTextBlockFormat::LineDistanceHeight: - html += QLatin1String(" line-spacing:"); + html += QLatin1String("; -qt-line-height-type: line-distance;"); break; - case QTextBlockFormat::SingleHeight: default: + html += QLatin1String(";"); break; // Should never reach here } - html += QString::number(format.lineHeight()); - if (format.lineHeightType() == QTextBlockFormat::ProportionalHeight) - html += QLatin1String("%;"); - else - html += QLatin1String("px;"); } emitPageBreakPolicy(format.pageBreakPolicy()); diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index d8e12f7024..576ff7d935 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -492,7 +492,7 @@ static QString quoteNewline(const QString &s) QTextHtmlParserNode::QTextHtmlParserNode() : parent(0), id(Html_unknown), - cssFloat(QTextFrameFormat::InFlow), hasOwnListStyle(false), + cssFloat(QTextFrameFormat::InFlow), hasOwnListStyle(false), hasOwnLineHeightType(false), hasCssListIndent(false), isEmptyParagraph(false), isTextFrame(false), isRootFrame(false), displayMode(QTextHtmlElement::DisplayInline), hasHref(false), listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0), @@ -1198,20 +1198,48 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector case QCss::QtBlockIndent: blockFormat.setIndent(decl.d->values.first().variant.toInt()); break; - case QCss::LineHeight: { + case QCss::QtLineHeightType: { + QString lineHeightTypeName = decl.d->values.first().variant.toString(); + QTextBlockFormat::LineHeightTypes lineHeightType; + if (lineHeightTypeName.compare(QLatin1String("proportional"), Qt::CaseInsensitive) == 0) + lineHeightType = QTextBlockFormat::ProportionalHeight; + else if (lineHeightTypeName.compare(QLatin1String("fixed"), Qt::CaseInsensitive) == 0) + lineHeightType = QTextBlockFormat::FixedHeight; + else if (lineHeightTypeName.compare(QLatin1String("minimum"), Qt::CaseInsensitive) == 0) + lineHeightType = QTextBlockFormat::MinimumHeight; + else if (lineHeightTypeName.compare(QLatin1String("line-distance"), Qt::CaseInsensitive) == 0) + lineHeightType = QTextBlockFormat::LineDistanceHeight; + else + lineHeightType = QTextBlockFormat::SingleHeight; + + blockFormat.setProperty(QTextBlockFormat::LineHeightType, lineHeightType); + hasOwnLineHeightType = true; + } + break; + case QCss::LineHeight: { qreal lineHeight; + QTextBlockFormat::LineHeightTypes lineHeightType; if (decl.realValue(&lineHeight, "px")) { - blockFormat.setLineHeight(lineHeight, QTextBlockFormat::FixedHeight); + lineHeightType = QTextBlockFormat::MinimumHeight; } else { bool ok; QString value = decl.d->values.first().toString(); lineHeight = value.toDouble(&ok); - if (ok) - blockFormat.setLineHeight(lineHeight, QTextBlockFormat::ProportionalHeight); - else - blockFormat.setLineHeight(0, QTextBlockFormat::SingleHeight); + if (ok) { + lineHeightType = QTextBlockFormat::ProportionalHeight; + } else { + lineHeight = 0.0; + lineHeightType = QTextBlockFormat::SingleHeight; + } } - break; } + + // Only override line height type if specified in same node + if (hasOwnLineHeightType) + lineHeightType = QTextBlockFormat::LineHeightTypes(blockFormat.lineHeightType()); + + blockFormat.setLineHeight(lineHeight, lineHeightType); + break; + } case QCss::TextIndent: { qreal indent = 0; if (decl.realValue(&indent, "px")) diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h index 8e5a90be0b..4c0dd967f9 100644 --- a/src/gui/text/qtexthtmlparser_p.h +++ b/src/gui/text/qtexthtmlparser_p.h @@ -171,6 +171,7 @@ struct QTextHtmlParserNode { QTextBlockFormat blockFormat; uint cssFloat : 2; uint hasOwnListStyle : 1; + uint hasOwnLineHeightType : 1; uint hasCssListIndent : 1; uint isEmptyParagraph : 1; uint isTextFrame : 1; -- cgit v1.2.3 From e12ba07322cd61c5cf50c25ed8d1f08f6b1ff879 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 24 Mar 2016 12:38:18 +0100 Subject: Update ANGLE to chromium/2651 Change-Id: I1cd32b780b1a0b913fab870e155ae1f4f9ac40d7 Reviewed-by: Maurice Kalinowski --- src/gui/opengl/qopengl.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/gui') diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h index 745adda969..5f9d78b780 100644 --- a/src/gui/opengl/qopengl.h +++ b/src/gui/opengl/qopengl.h @@ -100,6 +100,9 @@ typedef void* GLeglImageOES; # elif defined(QT_OPENGL_ES_3) # include # else +# ifndef GL_GLEXT_PROTOTYPES +# define GL_GLEXT_PROTOTYPES +# endif # include #endif -- cgit v1.2.3 From ebbfc556678f1c780e0bd1efde23835d023f95ad Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 24 Apr 2016 00:07:28 +0200 Subject: QtGui: mark more types as primitive/movable These types are held in QVarLengthArrays, so benefit from being trivially relocatable. They are also part of the private API, so there's no BC issues with potential uses of these types in QList, except for QPainter::PixmapFragment, which consequently has been marked as relocatable only. Change-Id: I90fb9a19231c6f5c71c593602fc997ffafe8f047 Reviewed-by: Lars Knoll --- src/gui/painting/qpaintengine.cpp | 3 +++ src/gui/painting/qpainter.h | 1 + src/gui/painting/qregion.cpp | 10 +++++++++- src/gui/text/qtextengine_p.h | 1 + src/gui/util/qgridlayoutengine_p.h | 1 + 5 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index d59d843f8a..020392409d 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -310,6 +310,7 @@ struct QT_Point { int x; int y; }; +Q_DECLARE_TYPEINFO(QT_Point, Q_PRIMITIVE_TYPE); /*! \fn void QPaintEngine::drawPolygon(const QPointF *points, int pointCount, @@ -340,6 +341,8 @@ struct QT_PointF { qreal x; qreal y; }; +Q_DECLARE_TYPEINFO(QT_PointF, Q_PRIMITIVE_TYPE); + /*! \overload diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index bd745e41ba..5743d97405 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -486,6 +486,7 @@ private: friend class QPreviewPaintEngine; friend class QTextEngine; }; +Q_DECLARE_TYPEINFO(QPainter::PixmapFragment, Q_RELOCATABLE_TYPE); Q_DECLARE_OPERATORS_FOR_FLAGS(QPainter::RenderHints) diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 35c4abb3ac..d38479c4b1 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -1047,7 +1047,15 @@ void addSegmentsToPath(Segment *segment, QPainterPath &path) } } -} +} // unnamed namespace + +// the following is really a lie, because Segments cannot be relocated, as they +// reference each other by address. For the same reason, they aren't even copyable, +// but the code works with the compiler-generated (wrong) copy and move special +// members, so use this as an optimization. The only container these are used in +// (a QVarLengthArray in qt_regionToPath()) is resized once up-front, so doesn't +// have a problem with this, but benefits from not having to run Segment ctors: +Q_DECLARE_TYPEINFO(Segment, Q_PRIMITIVE_TYPE); Q_GUI_EXPORT QPainterPath qt_regionToPath(const QRegion ®ion) { diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index ab08f2d5e5..56c9825cc1 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -180,6 +180,7 @@ struct QGlyphAttributes { uchar reserved : 2; }; Q_STATIC_ASSERT(sizeof(QGlyphAttributes) == 1); +Q_DECLARE_TYPEINFO(QGlyphAttributes, Q_PRIMITIVE_TYPE); struct QGlyphLayout { diff --git a/src/gui/util/qgridlayoutengine_p.h b/src/gui/util/qgridlayoutengine_p.h index b3ed2d287b..d79d4cc9c9 100644 --- a/src/gui/util/qgridlayoutengine_p.h +++ b/src/gui/util/qgridlayoutengine_p.h @@ -210,6 +210,7 @@ public: return *t; } }; +Q_DECLARE_TYPEINFO(QGridLayoutBox, Q_MOVABLE_TYPE); // cannot be Q_PRIMITIVE_TYPE, as q_maximumSize, say, is != 0 bool operator==(const QGridLayoutBox &box1, const QGridLayoutBox &box2); inline bool operator!=(const QGridLayoutBox &box1, const QGridLayoutBox &box2) -- cgit v1.2.3 From 0b35167c209481cfe6450c78b5dfb490280c428f Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 26 Apr 2016 10:56:53 +0200 Subject: QZipReader - test that QFile::open was, indeed, successful. Coverity, CIDs 10917, 10918. This fix looks like purely cosmetic and unneeded: we check f->error() after f->open(). Unfortunately, f->open() can fail without setting an error (if you provided an invalid mode). Change-Id: Idbfcb9305b3f004e5e425cb6076b41e193b8d473 Reviewed-by: Konstantin Ritt --- src/gui/text/qzip.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp index 31ef8f87be..a3112cc7fb 100644 --- a/src/gui/text/qzip.cpp +++ b/src/gui/text/qzip.cpp @@ -816,9 +816,8 @@ void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode) { QScopedPointer f(new QFile(archive)); - f->open(mode); QZipReader::Status status; - if (f->error() == QFile::NoError) + if (f->open(mode) && f->error() == QFile::NoError) status = NoError; else { if (f->error() == QFile::ReadError) @@ -1112,9 +1111,8 @@ void QZipReader::close() QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode) { QScopedPointer f(new QFile(fileName)); - f->open(mode); QZipWriter::Status status; - if (f->error() == QFile::NoError) + if (f->open(mode) && f->error() == QFile::NoError) status = QZipWriter::NoError; else { if (f->error() == QFile::WriteError) -- cgit v1.2.3 From cd964c04421042d430ef067608956e30ea5a5b74 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 4 Mar 2016 11:41:36 +0100 Subject: QPdf: replace a hand-written qWarning with Q_UNIMPLEMENTED But keep the 'Implement me' as a comment. Remove default label from the switch to indicate that the warning is only for the conical gradient case, and not for the NoGradient case. Also enables compiler warnings should we ever decide to add another gradient type. Change-Id: I891e652ff0293b4b4c254c7a55ebc6120b4fbcb6 Reviewed-by: Kai Koehne Reviewed-by: Giuseppe D'Angelo --- src/gui/painting/qpdf.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 10f0fcc21d..8189351bd8 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -2215,8 +2215,10 @@ int QPdfEnginePrivate::generateGradientShader(const QGradient *gradient, const Q case QGradient::RadialGradient: return generateRadialGradientShader(static_cast(gradient), matrix, alpha); case QGradient::ConicalGradient: - default: - qWarning("Implement me!"); + Q_UNIMPLEMENTED(); // ### Implement me! + break; + case QGradient::NoGradient: + break; } return 0; } -- cgit v1.2.3 From 31c7b24aa5f57fbe8258c9e9845c8d630af4aec1 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 1 Apr 2016 23:55:25 +0200 Subject: Silence MSVC warnings when using certain std algorithms The MSVC STL warns when passing naked pointers as non-bounded iterators to algorithms such as std::equal and std::copy, in an attempt to inform users that the range specified by that iterator has an implicit minimum size that the caller of the algorithm must ensure is met: warning C4996: 'std::_Equal1': Function call with parameters that may be unsafe - \ this call relies on the caller to check that the passed values are correct. To \ disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to \ use Visual C++ 'Checked Iterators' When building Qt, as well as when building user projects with qmake (cf. 0a76b6bc7f98900ea884cd10ccca1a332e5bdba5), we globally disable this warning (with -D_SCL_SECURE_NO_WARNINGS), but since we started using STL algorithms in public headers (e.g. in qvector.h), users get this warning in their own projects now, unless they, too, define said macro. But such a requirement is against the Qt policy to have headers that are warning-free as much as possible. The suggested way of fixing this warning is to wrap the naked pointer in a stdext::unchecked_array_iterator before passing it to the algorithm, cf. examples in https://msdn.microsoft.com/en-us/library/ttcz0bys%28v=vs.120%29.aspx or, together with the capacity-made-explicit, in a stdext::checked_array_iterator. To avoid ifdefs for platforms that don't have these extensions (which, incidentally, for the unchecked case, includes MSVC 2012), wrap the calls in macros. The end game here is to drop -D_SCL_SECURE_NO_WARNINGS, at least for public headers, even though this commit also adds the wrapper to implementation and private header files. An alternative to the wrapper would have been the version of std::equal that takes four iterators. However, that is a C++14 library feature, while this version of Qt still needs to compile with a C++98 compiler, and, more importantly, there isn't, and never will be, a corresponding 4-iterator version of std::copy. Task-number: QTBUG-47948 Done-with: Stephen Kelly Change-Id: I1bbab257fb5f1c5042939c382a412b596112ff26 Reviewed-by: Stephen Kelly --- src/gui/kernel/qkeysequence.cpp | 2 +- src/gui/kernel/qkeysequence_p.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 6bb80042ee..a0818b8d20 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -1637,7 +1637,7 @@ QDataStream &operator>>(QDataStream &s, QKeySequence &keysequence) s >> keys[i]; } qAtomicDetach(keysequence.d); - std::copy(keys, keys + MaxKeys, keysequence.d->key); + std::copy(keys, keys + MaxKeys, QT_MAKE_CHECKED_ARRAY_ITERATOR(keysequence.d->key, MaxKeys)); return s; } diff --git a/src/gui/kernel/qkeysequence_p.h b/src/gui/kernel/qkeysequence_p.h index 6d20f798b3..9525a343dc 100644 --- a/src/gui/kernel/qkeysequence_p.h +++ b/src/gui/kernel/qkeysequence_p.h @@ -70,7 +70,8 @@ public: } inline QKeySequencePrivate(const QKeySequencePrivate ©) : ref(1) { - std::copy(copy.key, copy.key + MaxKeyCount, key); + std::copy(copy.key, copy.key + MaxKeyCount, + QT_MAKE_CHECKED_ARRAY_ITERATOR(key, MaxKeyCount)); } QAtomicInt ref; int key[MaxKeyCount]; -- cgit v1.2.3 From c003a18ee332abf2387172eb0856a176a32a6c8f Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 26 Apr 2016 12:09:17 +0400 Subject: Fix font fallback for an overridden Common script cases Always prefer the requested font, even if it doesn't support the script of interest, and fallback to a font that *does* support that script, so that the best-matching font always takes a precedence. The result looks much closer to what CT and GDI/DW does. Task-number: QTBUG-35836 Task-number: QTBUG-39377 Task-number: QTBUG-43408 Change-Id: I6a89593565683f318f7292ec5ecf271dadc4142a Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfontdatabase.cpp | 4 ++-- src/gui/text/qfontdatabase.h | 1 + src/gui/text/qrawfont.cpp | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 629a098fb7..e4c9b45dc2 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -2669,7 +2669,7 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script) QtFontDesc desc; QList blackListed; - int index = match(script, request, family_name, foundry_name, &desc, blackListed); + int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed); if (index >= 0) { engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size); if (engine) @@ -2702,7 +2702,7 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script) if (!engine) { QtFontDesc desc; do { - index = match(script, def, def.family, QLatin1String(""), &desc, blackListed); + index = match(multi ? QChar::Script_Common : script, def, def.family, QLatin1String(""), &desc, blackListed); if (index >= 0) { QFontDef loadDef = def; if (loadDef.family.isEmpty()) diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 36e5677b92..67cf671304 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -167,6 +167,7 @@ private: friend class QFontDialog; friend class QFontDialogPrivate; friend class QFontEngineMulti; + friend class QRawFont; QFontDatabasePrivate *d; }; diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 2a53b8869d..19ac4f1dbc 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -700,6 +700,20 @@ QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writ if (fe != 0 && fe->type() == QFontEngine::Multi) { QFontEngineMulti *multiEngine = static_cast(fe); fe = multiEngine->engine(0); + + if (script > QChar::Script_Latin) { + // keep in sync with QFontEngineMulti::loadEngine() + QFontDef request(multiEngine->fontDef); + request.styleStrategy |= QFont::NoFontMerging; + + if (QFontEngine *engine = QFontDatabase::findFont(request, script)) { + if (request.weight > QFont::Normal) + engine->fontDef.weight = request.weight; + if (request.style > QFont::StyleNormal) + engine->fontDef.style = request.style; + fe = engine; + } + } Q_ASSERT(fe); } -- cgit v1.2.3 From 4077e28daa55652d7ada776b2702341125516caf Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 13 Apr 2016 15:33:03 +0200 Subject: Avoid processing bezier curves that will be clipped anyway Simplify curves ourside the clipped area with a straight line that closes the path, but saves us a lot of time and memory when zooming in on a path. Change-Id: I437f7eab564b805ebbefccd6755060156227c88d Reviewed-by: Gunnar Sletta --- src/gui/painting/qoutlinemapper.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp index 7245b44fc7..f1e4ce5820 100644 --- a/src/gui/painting/qoutlinemapper.cpp +++ b/src/gui/painting/qoutlinemapper.cpp @@ -78,10 +78,23 @@ void QOutlineMapper::curveTo(const QPointF &cp1, const QPointF &cp2, const QPoin #endif QBezier bezier = QBezier::fromPoints(m_elements.last(), cp1, cp2, ep); - bezier.addToPolygon(m_elements, m_curve_threshold); - m_element_types.reserve(m_elements.size()); - for (int i = m_elements.size() - m_element_types.size(); i; --i) - m_element_types << QPainterPath::LineToElement; + + bool outsideClip = false; + // Test one point first before doing a full intersection test. + if (!QRectF(m_clip_rect).contains(m_transform.map(ep))) { + QRectF potentialCurveArea = m_transform.mapRect(bezier.bounds()); + outsideClip = !potentialCurveArea.intersects(m_clip_rect); + } + if (outsideClip) { + // The curve is entirely outside the clip rect, so just + // approximate it with a line that closes the path. + lineTo(ep); + } else { + bezier.addToPolygon(m_elements, m_curve_threshold); + m_element_types.reserve(m_elements.size()); + for (int i = m_elements.size() - m_element_types.size(); i; --i) + m_element_types << QPainterPath::LineToElement; + } Q_ASSERT(m_elements.size() == m_element_types.size()); } -- cgit v1.2.3 From ab06266e15265737039cec2129fdf44848ed95a8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 25 Apr 2016 15:19:53 +0200 Subject: Fix clipping of wave underline decoration on certain fonts Limit the height of the the wave-pixmap so that fillRect doesn't clip it. At the same time the precision of the generated wave-pixmap is improved so it better fits the requested radius. Task-number: QTCREATORBUG-15851 Change-Id: If754387b20ab7b015857ecb0a0e8fe16de1d728a Reviewed-by: Konstantin Ritt Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/painting/qpainter.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 5dcab11f0a..baeee4dbfa 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -6179,7 +6179,8 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) QString key = QLatin1String("WaveUnderline-") % pen.color().name() - % HexString(radiusBase); + % HexString(radiusBase) + % HexString(pen.widthF()); QPixmap pixmap; if (QPixmapCache::find(key, pixmap)) @@ -6187,7 +6188,7 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod); - const int radius = qFloor(radiusBase); + const qreal radius = qFloor(radiusBase * 2) / 2.; QPainterPath path; @@ -6210,7 +6211,7 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) // due to it having a rather thick width for the regular underline. const qreal maxPenWidth = .8 * radius; if (wavePen.widthF() > maxPenWidth) - wavePen.setWidth(maxPenWidth); + wavePen.setWidthF(maxPenWidth); QPainter imgPainter(&pixmap); imgPainter.setPen(wavePen); @@ -6263,14 +6264,15 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const if (underlineStyle == QTextCharFormat::WaveUnderline) { painter->save(); painter->translate(0, pos.y() + 1); + qreal maxHeight = fe->descent().toReal() - qreal(1); QColor uc = charFormat.underlineColor(); if (uc.isValid()) pen.setColor(uc); // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms - const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen); - const int descent = (int) fe->descent().toReal(); + const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / 2.), pen); + const int descent = qFloor(maxHeight); painter->setBrushOrigin(painter->brushOrigin().x(), 0); painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave); -- cgit v1.2.3 From e91abaa48eb3c6269a0f34301b58d2c194cb6141 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 13 Apr 2016 17:19:56 +0200 Subject: Optimize convert_Indexed8_to_X32 Basic optimization of conversion from indexed8. Task-number: QTBUG-35747 Change-Id: Ic9d32789769eadb05fbecfebf2d2f2c87d66610b Reviewed-by: Gunnar Sletta --- src/gui/image/qimage_conversions.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 4f8e88adda..3c80b070e3 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -1734,24 +1734,30 @@ static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt: Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); - QVector colorTable = fix_color_table(src->colortable, dest->format); + QVector colorTable = src->has_alpha_clut ? fix_color_table(src->colortable, dest->format) : src->colortable; if (colorTable.size() == 0) { colorTable.resize(256); for (int i=0; i<256; ++i) colorTable[i] = qRgb(i, i, i); } + if (colorTable.size() < 256) { + int tableSize = colorTable.size(); + colorTable.resize(256); + for (int i=tableSize; i<256; ++i) + colorTable[i] = 0; + } int w = src->width; const uchar *src_data = src->data; uchar *dest_data = dest->data; - int tableSize = colorTable.size() - 1; + const QRgb *colorTablePtr = colorTable.constData(); for (int y = 0; y < src->height; y++) { - uint *p = (uint *)dest_data; + uint *p = reinterpret_cast(dest_data); const uchar *b = src_data; uint *end = p + w; while (p < end) - *p++ = colorTable.at(qMin(tableSize, *b++)); + *p++ = colorTablePtr[*b++]; src_data += src->bytes_per_line; dest_data += dest->bytes_per_line; -- cgit v1.2.3 From 8c2b7405b4a5f7d0fee62b78a17100529e611a5c Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Sun, 24 Apr 2016 19:52:37 +0200 Subject: QPdf: Force miter limit into valid range Miter limits below 1.0 are not valid in PDF and trigger an error in the Reader. This change enforces a minimum miter limit of 1.0, and it adds a manual test for producing a PDF file demonstrating this issue. Task-number: QTBUG-52641 Change-Id: I1c78b1c4a44579e95e1cddfb459926d304e60165 Reviewed-by: Lars Knoll --- src/gui/painting/qpdf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 22a387bd28..0df5fd8b8a 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -1196,7 +1196,7 @@ void QPdfEngine::setPen() switch(d->pen.joinStyle()) { case Qt::MiterJoin: case Qt::SvgMiterJoin: - *d->currentPage << d->pen.miterLimit() << "M "; + *d->currentPage << qMax(qreal(1.0), d->pen.miterLimit()) << "M "; pdfJoinStyle = 0; break; case Qt::BevelJoin: -- cgit v1.2.3 From d2304a28ca657634253af26ad803c7f292e6f4cc Mon Sep 17 00:00:00 2001 From: Jian Liang Date: Thu, 28 Apr 2016 22:14:20 +0800 Subject: Change some members of QFontEngineFT::Glyph to short Some color bitmap fonts will have a size greater than 127 pixels, areMetricsTooLarge() will return true(its advance exceed 127) for these fonts and we are unable to render these fonts since QFontEngineFT::loadGlyph() will simply do nothing if areMetricsTooLarge() return true. To support bitmap font whose size is between 128 and 255, we change x,y,advance of QFontEngineFT::Glyph to short variable to make areMetricsTooLarge() return false, in this way we will be able to render such color bitmap fonts. Change-Id: I9ab244b14884cdde91040a462f2fbca650b91289 Reviewed-by: Konstantin Ritt Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfontengine_ft.cpp | 5 +---- src/gui/text/qfontengine_ft_p.h | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 86fb0e8ae4..ec995d5cc6 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -849,11 +849,8 @@ static inline bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info) { // false if exceeds QFontEngineFT::Glyph metrics return (short)(info.linearAdvance) != info.linearAdvance - || (signed char)(info.xOff) != info.xOff || (uchar)(info.width) != info.width - || (uchar)(info.height) != info.height - || (signed char)(info.x) != info.x - || (signed char)(info.y) != info.y; + || (uchar)(info.height) != info.height; } QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 3421c873d5..ee2df6f665 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -140,9 +140,9 @@ public: short linearAdvance; unsigned char width; unsigned char height; - signed char x; - signed char y; - signed char advance; + short x; + short y; + short advance; signed char format; uchar *data; }; -- cgit v1.2.3 From 9180797247ebad855bf9713dd5574f9eef5296f2 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Wed, 27 Apr 2016 10:41:56 +0200 Subject: Add QInputMethod::inputItemClipRectangle() This property allows a convenient way of getting notified about changes in the input item clipped rectangle, similar to QIM::cursorRectangle(). Change-Id: I26bf97eeb1f5ef1b7d3aafb03565023091d6df3d Reviewed-by: Richard Moe Gustavsen --- src/gui/kernel/qinputmethod.cpp | 14 ++++++++++++++ src/gui/kernel/qinputmethod.h | 4 ++++ 2 files changed, 18 insertions(+) (limited to 'src/gui') diff --git a/src/gui/kernel/qinputmethod.cpp b/src/gui/kernel/qinputmethod.cpp index b81e166d3a..365b088840 100644 --- a/src/gui/kernel/qinputmethod.cpp +++ b/src/gui/kernel/qinputmethod.cpp @@ -182,6 +182,18 @@ QRectF QInputMethod::keyboardRectangle() const return QRectF(); } +/*! + \property QInputMethod::inputItemClipRectangle + \brief Input item's clipped rectangle in window coordinates. + + The clipped input rectangle is often used by various input methods to determine + how much screen real estate is available for the input method (e.g. Virtual Keyboard). +*/ +QRectF QInputMethod::inputItemClipRectangle() const +{ + Q_D(const QInputMethod); + return inputMethodQueryRectangle_helper(Qt::ImInputItemClipRectangle, d->inputItemTransform); +} /*! Requests virtual keyboard to open. If the platform doesn't provide virtual keyboard the visibility @@ -320,6 +332,8 @@ void QInputMethod::update(Qt::InputMethodQueries queries) if (queries & (Qt::ImAnchorRectangle)) emit anchorRectangleChanged(); + if (queries & (Qt::ImInputItemClipRectangle)) + emit inputItemClipRectangleChanged(); } /*! diff --git a/src/gui/kernel/qinputmethod.h b/src/gui/kernel/qinputmethod.h index 22e4677eaa..1a63d1314e 100644 --- a/src/gui/kernel/qinputmethod.h +++ b/src/gui/kernel/qinputmethod.h @@ -57,6 +57,7 @@ class Q_GUI_EXPORT QInputMethod : public QObject Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QRectF anchorRectangle READ anchorRectangle NOTIFY anchorRectangleChanged) Q_PROPERTY(QRectF keyboardRectangle READ keyboardRectangle NOTIFY keyboardRectangleChanged) + Q_PROPERTY(QRectF inputItemClipRectangle READ inputItemClipRectangle NOTIFY inputItemClipRectangleChanged) Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged) Q_PROPERTY(bool animating READ isAnimating NOTIFY animatingChanged) Q_PROPERTY(QLocale locale READ locale NOTIFY localeChanged) @@ -76,6 +77,8 @@ public: // keyboard geometry in window coords QRectF keyboardRectangle() const; + QRectF inputItemClipRectangle() const; + enum Action { Click, ContextMenu @@ -106,6 +109,7 @@ Q_SIGNALS: void cursorRectangleChanged(); void anchorRectangleChanged(); void keyboardRectangleChanged(); + void inputItemClipRectangleChanged(); void visibleChanged(); void animatingChanged(); void localeChanged(); -- cgit v1.2.3 From 63169fc893973437696ad49c4e3dfdd28e356f37 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 28 Apr 2016 13:28:51 +0200 Subject: Fix underline position on Liberation Mono Ensure we don't round a underline position beyond the descent in our eagerness to avoid underlines too close to baseline. Task-number: QTCREATORBUG-15851 Change-Id: I9a29447bbcb938b7e9fb29d52fd392a1340d07c5 Reviewed-by: Konstantin Ritt Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/painting/qpainter.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index baeee4dbfa..62254213f3 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -6251,9 +6251,6 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const painter->setRenderHint(QPainter::Qt4CompatiblePainting, false); const qreal underlineOffset = fe->underlinePosition().toReal(); - // deliberately ceil the offset to avoid the underline coming too close to - // the text above it. - const qreal underlinePos = pos.y() + qCeil(underlineOffset) + 0.5; if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme(); @@ -6278,6 +6275,12 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave); painter->restore(); } else if (underlineStyle != QTextCharFormat::NoUnderline) { + // Deliberately ceil the offset to avoid the underline coming too close to + // the text above it, but limit it to stay within descent. + qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + 0.5; + if (underlineOffset <= fe->descent().toReal()) + adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - 0.5); + const qreal underlinePos = pos.y() + adjustedUnderlineOffset; QColor uc = charFormat.underlineColor(); if (uc.isValid()) pen.setColor(uc); -- cgit v1.2.3 From 6efa3215a2724415ec7c11e3631594ada1b722b0 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 15 Apr 2016 16:51:04 +0200 Subject: QOpenGLCustomShaderStage - fix a memory leak Coverity found a memory leak - CID-10995. Fix a dtor + make copy constructor / assignment operator private (Q_DISABLE_COPY). Change-Id: I4f046d075b60fbfb69f350e4a4d8b07ea1643914 Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopenglcustomshaderstage.cpp | 1 + src/gui/opengl/qopenglcustomshaderstage_p.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'src/gui') diff --git a/src/gui/opengl/qopenglcustomshaderstage.cpp b/src/gui/opengl/qopenglcustomshaderstage.cpp index e0d131e64d..e5504e6195 100644 --- a/src/gui/opengl/qopenglcustomshaderstage.cpp +++ b/src/gui/opengl/qopenglcustomshaderstage.cpp @@ -63,6 +63,7 @@ QOpenGLCustomShaderStage::~QOpenGLCustomShaderStage() d->m_manager->removeCustomStage(); d->m_manager->sharedShaders->cleanupCustomStage(this); } + delete d_ptr; } void QOpenGLCustomShaderStage::setUniformsDirty() diff --git a/src/gui/opengl/qopenglcustomshaderstage_p.h b/src/gui/opengl/qopenglcustomshaderstage_p.h index 78c414d316..9b3c9fbce1 100644 --- a/src/gui/opengl/qopenglcustomshaderstage_p.h +++ b/src/gui/opengl/qopenglcustomshaderstage_p.h @@ -46,6 +46,7 @@ // #include +#include QT_BEGIN_NAMESPACE @@ -72,6 +73,8 @@ protected: private: QOpenGLCustomShaderStagePrivate* d_ptr; + + Q_DISABLE_COPY(QOpenGLCustomShaderStage) }; -- cgit v1.2.3 From 347832d7593e2369f8597bbd06213b80b3087433 Mon Sep 17 00:00:00 2001 From: Jian Liang Date: Fri, 1 Apr 2016 22:03:15 +0800 Subject: Support color font rendering for freetype engine This patch mainly do two things: 1) Support color bitmap font for freetype fontengine. This partially based on Corentin Jabot's patch 2) Support ARGB opengl glyph cache when workaround_brokenFBOReadBack is true (It is always true under Android). Some code refactor has been done in QOpenGLTextureGlyphCache. This patch also bump the minimal required freetype version to 2.2 [ChangeLog][General][Freetype] Support color font rendering Task-number: QTBUG-35156 Change-Id: I35aae5f98ba9a27b70a48db3f2647fc070c39c33 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/opengl/qopengltextureglyphcache.cpp | 171 ++++++++++---------- src/gui/text/qfontengine_ft.cpp | 234 ++++++++++++++++++++++------ src/gui/text/qfontengine_ft_p.h | 7 + 3 files changed, 285 insertions(+), 127 deletions(-) (limited to 'src/gui') diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp index 8f69095464..9a7b1eb21d 100644 --- a/src/gui/opengl/qopengltextureglyphcache.cpp +++ b/src/gui/opengl/qopengltextureglyphcache.cpp @@ -181,6 +181,94 @@ void QOpenGLTextureGlyphCache::setupVertexAttribs() m_buffer.release(); } +static void load_glyph_image_to_texture(QOpenGLContext *ctx, + QImage &img, + GLuint texture, + int tx, int ty) +{ + QOpenGLFunctions *funcs = ctx->functions(); + + const int imgWidth = img.width(); + const int imgHeight = img.height(); + + if (img.format() == QImage::Format_Mono) { + img = img.convertToFormat(QImage::Format_Grayscale8); + } else if (img.depth() == 32) { + if (img.format() == QImage::Format_RGB32 + // We need to make the alpha component equal to the average of the RGB values. + // This is needed when drawing sub-pixel antialiased text on translucent targets. +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + || img.format() == QImage::Format_ARGB32_Premultiplied +#else + || (img.format() == QImage::Format_ARGB32_Premultiplied + && ctx->isOpenGLES()) +#endif + ) { + for (int y = 0; y < imgHeight; ++y) { + QRgb *src = (QRgb *) img.scanLine(y); + for (int x = 0; x < imgWidth; ++x) { + int r = qRed(src[x]); + int g = qGreen(src[x]); + int b = qBlue(src[x]); + int avg; + if (img.format() == QImage::Format_RGB32) + avg = (r + g + b + 1) / 3; // "+1" for rounding. + else // Format_ARGB_Premultiplied + avg = qAlpha(src[x]); + + src[x] = qRgba(r, g, b, avg); + // swizzle the bits to accommodate for the GL_RGBA upload. +#if Q_BYTE_ORDER != Q_BIG_ENDIAN + if (ctx->isOpenGLES()) +#endif + src[x] = ARGB2RGBA(src[x]); + } + } + } + } + + funcs->glBindTexture(GL_TEXTURE_2D, texture); + if (img.depth() == 32) { +#ifdef QT_OPENGL_ES_2 + GLenum fmt = GL_RGBA; +#else + GLenum fmt = ctx->isOpenGLES() ? GL_RGBA : GL_BGRA; +#endif // QT_OPENGL_ES_2 + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + fmt = GL_RGBA; +#endif + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, fmt, GL_UNSIGNED_BYTE, img.constBits()); + } else { + // The scanlines in image are 32-bit aligned, even for mono or 8-bit formats. This + // is good because it matches the default of 4 bytes for GL_UNPACK_ALIGNMENT. +#if !defined(QT_OPENGL_ES_2) + const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA; +#else + const GLenum format = GL_ALPHA; +#endif + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, format, GL_UNSIGNED_BYTE, img.constBits()); + } +} + +static void load_glyph_image_region_to_texture(QOpenGLContext *ctx, + const QImage &srcImg, + int x, int y, + int w, int h, + GLuint texture, + int tx, int ty) +{ + Q_ASSERT(x + w <= srcImg.width() && y + h <= srcImg.height()); + + QImage img; + if (x != 0 || y != 0 || w != srcImg.width() || h != srcImg.height()) + img = srcImg.copy(x, y, w, h); + else + img = srcImg; + + load_glyph_image_to_texture(ctx, img, texture, tx, ty); +} + void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height) { QOpenGLContext *ctx = QOpenGLContext::currentContext(); @@ -207,9 +295,8 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height) if (ctx->d_func()->workaround_brokenFBOReadBack) { QImageTextureGlyphCache::resizeTextureData(width, height); - Q_ASSERT(image().depth() == 8); - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits()); - funcs->glDeleteTextures(1, &oldTexture); + load_glyph_image_region_to_texture(ctx, image(), 0, 0, qMin(oldWidth, width), qMin(oldHeight, height), + m_textureResource->m_texture, 0, 0); return; } @@ -336,88 +423,14 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed return; } - QOpenGLFunctions *funcs = ctx->functions(); if (ctx->d_func()->workaround_brokenFBOReadBack) { QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition); - - funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); - const QImage &texture = image(); - const uchar *bits = texture.constBits(); - bits += c.y * texture.bytesPerLine() + c.x; - for (int i=0; iglTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits); - bits += texture.bytesPerLine(); - } + load_glyph_image_region_to_texture(ctx, image(), c.x, c.y, c.w, c.h, m_textureResource->m_texture, c.x, c.y); return; } QImage mask = textureMapForGlyph(glyph, subPixelPosition); - const int maskWidth = mask.width(); - const int maskHeight = mask.height(); - - if (mask.format() == QImage::Format_Mono) { - mask = mask.convertToFormat(QImage::Format_Indexed8); - for (int y = 0; y < maskHeight; ++y) { - uchar *src = (uchar *) mask.scanLine(y); - for (int x = 0; x < maskWidth; ++x) - src[x] = -src[x]; // convert 0 and 1 into 0 and 255 - } - } else if (mask.depth() == 32) { - if (mask.format() == QImage::Format_RGB32 - // We need to make the alpha component equal to the average of the RGB values. - // This is needed when drawing sub-pixel antialiased text on translucent targets. -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - || mask.format() == QImage::Format_ARGB32_Premultiplied -#else - || (mask.format() == QImage::Format_ARGB32_Premultiplied - && ctx->isOpenGLES()) -#endif - ) { - for (int y = 0; y < maskHeight; ++y) { - QRgb *src = (QRgb *) mask.scanLine(y); - for (int x = 0; x < maskWidth; ++x) { - int r = qRed(src[x]); - int g = qGreen(src[x]); - int b = qBlue(src[x]); - int avg; - if (mask.format() == QImage::Format_RGB32) - avg = (r + g + b + 1) / 3; // "+1" for rounding. - else // Format_ARGB_Premultiplied - avg = qAlpha(src[x]); - - src[x] = qRgba(r, g, b, avg); - // swizzle the bits to accommodate for the GL_RGBA upload. -#if Q_BYTE_ORDER != Q_BIG_ENDIAN - if (ctx->isOpenGLES()) -#endif - src[x] = ARGB2RGBA(src[x]); - } - } - } - } - - funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); - if (mask.depth() == 32) { -#ifdef QT_OPENGL_ES_2 - GLenum fmt = GL_RGBA; -#else - GLenum fmt = ctx->isOpenGLES() ? GL_RGBA : GL_BGRA; -#endif // QT_OPENGL_ES_2 - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - fmt = GL_RGBA; -#endif - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, fmt, GL_UNSIGNED_BYTE, mask.bits()); - } else { - // The scanlines in mask are 32-bit aligned, even for mono or 8-bit formats. This - // is good because it matches the default of 4 bytes for GL_UNPACK_ALIGNMENT. -#if !defined(QT_OPENGL_ES_2) - const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA; -#else - const GLenum format = GL_ALPHA; -#endif - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, format, GL_UNSIGNED_BYTE, mask.bits()); - } + load_glyph_image_to_texture(ctx, mask, m_textureResource->m_texture, c.x, c.y); } int QOpenGLTextureGlyphCache::glyphPadding() const diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index ec995d5cc6..e89522f5af 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -52,6 +52,7 @@ #include #include "qthreadstorage.h" #include +#include #include #include FT_FREETYPE_H @@ -192,6 +193,15 @@ int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QF return Err_Ok; } +bool QFreetypeFace::isScalableBitmap() const +{ +#ifdef FT_HAS_COLOR + return !FT_IS_SCALABLE(face) && FT_HAS_COLOR(face); +#else + return false; +#endif +} + extern QByteArray qt_fontdata_from_index(int); /* @@ -249,6 +259,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, newFreetype->ref.store(1); newFreetype->xsize = 0; newFreetype->ysize = 0; + newFreetype->scalableBitmapScaleFactor = 1; newFreetype->matrix.xx = 0x10000; newFreetype->matrix.yy = 0x10000; newFreetype->matrix.xy = 0; @@ -330,36 +341,46 @@ void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, *xsize = *ysize * fontDef.stretch / 100; *outline_drawing = false; - /* - * Bitmap only faces must match exactly, so find the closest - * one (height dominant search) - */ if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) { int best = 0; - for (int i = 1; i < face->num_fixed_sizes; i++) { - if (qAbs(*ysize - face->available_sizes[i].y_ppem) < - qAbs(*ysize - face->available_sizes[best].y_ppem) || - (qAbs(*ysize - face->available_sizes[i].y_ppem) == - qAbs(*ysize - face->available_sizes[best].y_ppem) && - qAbs(*xsize - face->available_sizes[i].x_ppem) < - qAbs(*xsize - face->available_sizes[best].x_ppem))) { - best = i; + if (!isScalableBitmap()) { + /* + * Bitmap only faces must match exactly, so find the closest + * one (height dominant search) + */ + for (int i = 1; i < face->num_fixed_sizes; i++) { + if (qAbs(*ysize - face->available_sizes[i].y_ppem) < + qAbs(*ysize - face->available_sizes[best].y_ppem) || + (qAbs(*ysize - face->available_sizes[i].y_ppem) == + qAbs(*ysize - face->available_sizes[best].y_ppem) && + qAbs(*xsize - face->available_sizes[i].x_ppem) < + qAbs(*xsize - face->available_sizes[best].x_ppem))) { + best = i; + } + } + } else { + // Select the shortest bitmap strike whose height is larger than the desired height + for (int i = 1; i < face->num_fixed_sizes; i++) { + if (face->available_sizes[i].y_ppem < *ysize) { + if (face->available_sizes[i].y_ppem > face->available_sizes[best].y_ppem) + best = i; + } else if (face->available_sizes[best].y_ppem < *ysize) { + best = i; + } else if (face->available_sizes[i].y_ppem < face->available_sizes[best].y_ppem) { + best = i; + } } } - if (FT_Set_Char_Size(face, face->available_sizes[best].x_ppem, face->available_sizes[best].y_ppem, 0, 0) == 0) { + + // According to freetype documentation we must use FT_Select_Size + // to make sure we can select the desired bitmap strike index + if (FT_Select_Size(face, best) == 0) { + if (isScalableBitmap()) + scalableBitmapScaleFactor = QFixed::fromReal((qreal)fontDef.pixelSize / face->available_sizes[best].height); *xsize = face->available_sizes[best].x_ppem; *ysize = face->available_sizes[best].y_ppem; } else { - int err = 1; - if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) { - // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property - err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height); - if (err && face->num_fixed_sizes == 1) - err = 0; //even more of a workaround... - } - - if (err) - *xsize = *ysize = 0; + *xsize = *ysize = 0; } } else { *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6)); @@ -736,6 +757,11 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, if (line_thickness < 2 && score >= 1050) line_thickness = 2; underline_position = ((line_thickness * 2) + 3) / 6; + + if (isScalableBitmap()) { + glyphFormat = defaultFormat = GlyphFormat::Format_ARGB; + cacheEnabled = false; + } } if (line_thickness < 1) line_thickness = 1; @@ -829,6 +855,10 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, load_target = FT_LOAD_TARGET_LCD_V; vfactor = 3; } + } else if (format == Format_ARGB) { +#ifdef FT_LOAD_COLOR + load_flags |= FT_LOAD_COLOR; +#endif } if (set && set->outline_drawing) @@ -890,7 +920,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, || matrix.xy != 0 || matrix.yx != 0; - if (transform || (format != Format_Mono && !embeddedbitmap)) + if (transform || (format != Format_Mono && !isScalableBitmap())) load_flags |= FT_LOAD_NO_BITMAP; FT_Error err = FT_Load_Glyph(face, glyph, load_flags); @@ -1121,7 +1151,11 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, if (bitmap.buffer != glyph_buffer.data()) delete [] bitmap.buffer; } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) { +#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500) + Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO || slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA); +#else Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO); +#endif uchar *src = slot->bitmap.buffer; uchar *dst = glyph_buffer.data(); int h = slot->bitmap.rows; @@ -1132,7 +1166,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, dst += pitch; src += slot->bitmap.pitch; } - } else { + } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { if (hsubpixel) { while (h--) { uint *dd = (uint *)dst; @@ -1166,6 +1200,29 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, } } } +#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500) + else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + while (h--) { +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + const quint32 *srcPixel = (const quint32 *)src; + quint32 *dstPixel = (quint32 *)dst; + for (int x = 0; x < static_cast(slot->bitmap.width); x++, srcPixel++, dstPixel++) { + const quint32 pixel = *srcPixel; + *dstPixel = qbswap(pixel); + } +#else + memcpy(dst, src, slot->bitmap.width * 4); +#endif + dst += slot->bitmap.pitch; + src += slot->bitmap.pitch; + } + info.width = info.linearAdvance = info.xOff = slot->bitmap.width; + info.height = slot->bitmap.rows; + info.x = slot->bitmap_left; + info.y = slot->bitmap_top; + } +#endif } else { qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format); return 0; @@ -1236,46 +1293,68 @@ int QFontEngineFT::synthesized() const QFixed QFontEngineFT::ascent() const { - return QFixed::fromFixed(metrics.ascender); + QFixed v = QFixed::fromFixed(metrics.ascender); + if (freetype->scalableBitmapScaleFactor != 1) + v *= freetype->scalableBitmapScaleFactor; + return v; } QFixed QFontEngineFT::descent() const { - return QFixed::fromFixed(-metrics.descender); + QFixed v = QFixed::fromFixed(-metrics.descender); + if (freetype->scalableBitmapScaleFactor != 1) + v *= freetype->scalableBitmapScaleFactor; + return v; } QFixed QFontEngineFT::leading() const { - return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender); + QFixed v = QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender); + if (freetype->scalableBitmapScaleFactor != 1) + v *= freetype->scalableBitmapScaleFactor; + return v; } QFixed QFontEngineFT::xHeight() const { - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); - if (os2 && os2->sxHeight) { - lockFace(); - QFixed answer = QFixed(os2->sxHeight * freetype->face->size->metrics.y_ppem) / emSquareSize(); - unlockFace(); - return answer; + if (!isScalableBitmap()) { + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); + if (os2 && os2->sxHeight) { + lockFace(); + QFixed answer = QFixed(os2->sxHeight * freetype->face->size->metrics.y_ppem) / emSquareSize(); + unlockFace(); + return answer; + } + } else { + return QFixed(freetype->face->size->metrics.y_ppem) * freetype->scalableBitmapScaleFactor; } return QFontEngine::xHeight(); } QFixed QFontEngineFT::averageCharWidth() const { - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); - if (os2 && os2->xAvgCharWidth) { - lockFace(); - QFixed answer = QFixed(os2->xAvgCharWidth * freetype->face->size->metrics.x_ppem) / emSquareSize(); - unlockFace(); - return answer; - } - return QFontEngine::averageCharWidth(); + if (!isScalableBitmap()) { + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); + if (os2 && os2->xAvgCharWidth) { + lockFace(); + QFixed answer = QFixed(os2->xAvgCharWidth * freetype->face->size->metrics.x_ppem) / emSquareSize(); + unlockFace(); + return answer; + } + } else { + const qreal aspectRatio = (qreal)xsize / ysize; + return QFixed::fromReal(fontDef.pixelSize * aspectRatio); + } + + return QFontEngine::averageCharWidth(); } qreal QFontEngineFT::maxCharWidth() const { - return metrics.max_advance >> 6; + QFixed max_advance = QFixed::fromFixed(metrics.max_advance); + if (freetype->scalableBitmapScaleFactor != 1) + max_advance *= freetype->scalableBitmapScaleFactor; + return max_advance.toReal(); } QFixed QFontEngineFT::lineThickness() const @@ -1558,6 +1637,23 @@ bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const return default_hint_style == HintNone || default_hint_style == HintLight || (flags & DesignMetrics); } +QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const +{ + return m * freetype->scalableBitmapScaleFactor; +} + +glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m) const +{ + glyph_metrics_t metrics; + metrics.x = scaledBitmapMetrics(m.x); + metrics.y = scaledBitmapMetrics(m.y); + metrics.width = scaledBitmapMetrics(m.width); + metrics.height = scaledBitmapMetrics(m.height); + metrics.xoff = scaledBitmapMetrics(m.xoff); + metrics.yoff = scaledBitmapMetrics(m.yoff); + return metrics; +} + void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const { FT_Face face = 0; @@ -1580,6 +1676,9 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag if (!cacheEnabled && g != &emptyGlyph) delete g; } + + if (freetype->scalableBitmapScaleFactor != 1) + glyphs->advances[i] *= freetype->scalableBitmapScaleFactor; } if (face) unlockFace(); @@ -1596,8 +1695,13 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs) glyph_metrics_t overall; // initialize with line height, we get the same behaviour on all platforms - overall.y = -ascent(); - overall.height = ascent() + descent(); + if (!isScalableBitmap()) { + overall.y = -ascent(); + overall.height = ascent() + descent(); + } else { + overall.y = QFixed::fromFixed(-metrics.ascender); + overall.height = QFixed::fromFixed(metrics.ascender - metrics.descender); + } QFixed ymax = 0; QFixed xmax = 0; @@ -1639,6 +1743,8 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs) if (face) unlockFace(); + if (isScalableBitmap()) + overall = scaledBitmapMetrics(overall); return overall; } @@ -1675,6 +1781,9 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph) } if (face) unlockFace(); + + if (isScalableBitmap()) + overall = scaledBitmapMetrics(overall); return overall; } @@ -1710,6 +1819,9 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe overall.xoff = TRUNC(ROUND(face->glyph->advance.x)); unlockFace(); } + + if (isScalableBitmap()) + overall = scaledBitmapMetrics(overall); return overall; } @@ -1857,6 +1969,31 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, co return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); } +QImage QFontEngineFT::bitmapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) +{ + Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t); + if (glyph == Q_NULLPTR) + return QImage(); + + QImage img; + if (defaultFormat == GlyphFormat::Format_ARGB) + img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_ARGB32_Premultiplied).copy(); + else if (defaultFormat == GlyphFormat::Format_Mono) + img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_Mono).copy(); + + if (!img.isNull() && (!t.isIdentity() || freetype->scalableBitmapScaleFactor != 1)) { + QTransform trans(t); + const qreal scaleFactor = freetype->scalableBitmapScaleFactor.toReal(); + trans.scale(scaleFactor, scaleFactor); + img = img.transformed(trans, Qt::SmoothTransformation); + } + + if (!cacheEnabled && glyph != &emptyGlyph) + delete glyph; + + return img; +} + void QFontEngineFT::removeGlyphFromCache(glyph_t glyph) { defaultGlyphSet.removeGlyphFromCache(glyph, 0); @@ -1878,9 +2015,10 @@ FT_Face QFontEngineFT::lockFace(Scaling scale) const freetype->lock(); FT_Face face = freetype->face; if (scale == Unscaled) { - FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0); - freetype->xsize = face->units_per_EM << 6; - freetype->ysize = face->units_per_EM << 6; + if (FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0) == 0) { + freetype->xsize = face->units_per_EM << 6; + freetype->ysize = face->units_per_EM << 6; + } } else if (freetype->xsize != xsize || freetype->ysize != ysize) { FT_Set_Char_Size(face, xsize, ysize, 0, 0); freetype->xsize = xsize; diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index ee2df6f665..3f4bf84753 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -96,6 +96,7 @@ public: FT_Face face; int xsize; // 26.6 int ysize; // 26.6 + QFixed scalableBitmapScaleFactor; FT_Matrix matrix; FT_CharMap unicode_map; FT_CharMap symbol_map; @@ -107,6 +108,8 @@ public: int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints); + bool isScalableBitmap() const; + static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale); static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path); @@ -239,6 +242,7 @@ private: QImage alphaMapForGlyph(glyph_t, QFixed) Q_DECL_OVERRIDE; QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; + QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, @@ -266,6 +270,7 @@ private: inline bool drawAntialiased() const { return antialias; } inline bool invalid() const { return xsize == 0 && ysize == 0; } inline bool isBitmapFont() const { return defaultFormat == Format_Mono; } + inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); } inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const { return loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, subPixelPosition, format, fetchMetricsOnly); } @@ -316,6 +321,8 @@ private: int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const; bool shouldUseDesignMetrics(ShaperFlags flags) const; + QFixed scaledBitmapMetrics(QFixed m) const; + glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m) const; GlyphFormat defaultFormat; FT_Matrix matrix; -- cgit v1.2.3 From b75e10684cb4d14e49059e6c85bfe60ca6ab9dff Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 4 May 2016 09:57:46 +0200 Subject: doc: Clarify how to remove a QTextFrame The documentation wrongfully recommended deleting QTextFrames directly. This would cause a crash, since the destructor didn't update the document's layout at all. The correct way is the same as when removing other aspects of the document. Task-number: QTBUG-53082 Change-Id: I64f0ad08f1d063626456fa51d03611871ce6aa45 Reviewed-by: Simon Hausmann --- src/gui/text/qtextobject.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index e70b8ed300..e1cfd22295 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -412,9 +412,12 @@ QTextFrame::QTextFrame(QTextDocument *doc) { } -// ### DOC: What does this do to child frames? /*! - Destroys the frame, and removes it from the document's layout. + Destroys the text frame. + + \warning Text frames are owned by the document, so you should + never destroy them yourself. In order to remove a frame from + its document, remove its contents using a \c QTextCursor. */ QTextFrame::~QTextFrame() { -- cgit v1.2.3 From 8d45759432e7f954360b76ddeaf2b09acee8606e Mon Sep 17 00:00:00 2001 From: Elena Zaretskaya Date: Fri, 8 Apr 2016 12:29:25 +0400 Subject: Fix segfault when exiting app running under eglfs In function QWindow::destroy() the platformWindow is destroyed (QEglFSWindow in this case), but after that the QSurface destructor is called (qsurface.cpp:127), where access to the opengl context is performed (QOpenGLContext::currentContext()->doneCurrent()). Therefore the surface pointer is deleted earlier (gbm_surface_destroy) than the working with it (eglMakeCurrent) is finished. But the event QPlatformSurfaceEvent, that is sent before deleting platformWindow, isn't processed (qwindow.cpp:1665), though we can perform doneCurrent() in the handler of QPlatformSurfaceEvent. The full description with valgrind stacks on bugreports. Task-number: QTBUG-52399 Change-Id: I69035dfd8ba5b5eeec243bc0edd3f571dc9525f9 Reviewed-by: Laszlo Agocs --- src/gui/kernel/qwindow.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/gui') diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 68bcbdec71..7f84706b6f 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2109,6 +2109,17 @@ bool QWindow::event(QEvent *ev) break; } + case QEvent::PlatformSurface: { + if ((static_cast(ev))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) { +#ifndef QT_NO_OPENGL + QOpenGLContext *context = QOpenGLContext::currentContext(); + if (context && context->surface() == static_cast(this)) + context->doneCurrent(); +#endif + } + break; + } + default: return QObject::event(ev); } -- cgit v1.2.3 From e54c74e3f0feb38737efc95793d46b84d2d3f3cd Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2016 09:51:24 +0200 Subject: QImageWriter: use new QJsonObject::value(QLatin1String) Allows to get rid of some QStringLiterals, reducing QtGui text size by ~200b. Change-Id: I0f3a84c1c8ee6771d8e1f2c6284d314b3fc0c28a Reviewed-by: Lars Knoll --- src/gui/image/qimagewriter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index b60cf59864..35db038601 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -854,9 +854,9 @@ void supportedImageHandlerMimeTypes(QFactoryLoader *loader, const int pluginCount = metaDataList.size(); for (int i = 0; i < pluginCount; ++i) { - const QJsonObject metaData = metaDataList.at(i).value(QStringLiteral("MetaData")).toObject(); - const QJsonArray keys = metaData.value(QStringLiteral("Keys")).toArray(); - const QJsonArray mimeTypes = metaData.value(QStringLiteral("MimeTypes")).toArray(); + const QJsonObject metaData = metaDataList.at(i).value(QLatin1String("MetaData")).toObject(); + const QJsonArray keys = metaData.value(QLatin1String("Keys")).toArray(); + const QJsonArray mimeTypes = metaData.value(QLatin1String("MimeTypes")).toArray(); QImageIOPlugin *plugin = qobject_cast(loader->instance(i)); const int keyCount = keys.size(); for (int k = 0; k < keyCount; ++k) { -- cgit v1.2.3 From e64b2234e829cc47872225debcf80d6c06db18f0 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 10 May 2016 14:47:31 +0200 Subject: QImage::setPixelColor: warn about invalid colors Task-number: QTBUG-52142 Change-Id: I9f390bd332f8edabaece75a6b36830c691ff4b9e Reviewed-by: Gunnar Sletta --- src/gui/image/qimage.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 64a53b4c0e..2911477d28 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -2455,10 +2455,16 @@ QColor QImage::pixelColor(int x, int y) const */ void QImage::setPixelColor(int x, int y, const QColor &color) { - if (!d || x < 0 || x >= width() || y < 0 || y >= height() || !color.isValid()) { + if (!d || x < 0 || x >= width() || y < 0 || y >= height()) { qWarning("QImage::setPixelColor: coordinate (%d,%d) out of range", x, y); return; } + + if (!color.isValid()) { + qWarning("QImage::setPixelColor: color is invalid"); + return; + } + // QColor is always unpremultiplied QRgba64 c = color.rgba64(); if (!hasAlphaChannel()) -- cgit v1.2.3