summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-05-12 07:31:50 +0200
committerLiang Qi <liang.qi@qt.io>2016-05-12 08:33:08 +0200
commit990969655c5fb4d03682e96df9b12101f5ee9815 (patch)
treeb8fb5c50285105c8bc5a938fb50f93ff9f24889d /src/gui
parenta213011a53f12f101d08a04afc8fdacd2d54a232 (diff)
parente64b2234e829cc47872225debcf80d6c06db18f0 (diff)
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts: config_help.txt configure src/corelib/io/qprocess_wince.cpp src/plugins/platforms/windows/qwindowstheme.cpp src/plugins/platforms/xcb/qxcbbackingstore.cpp tests/auto/corelib/tools/qtimezone/BLACKLIST tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp Change-Id: I26644d1cb3b78412c8ff285e2a55bea1bd641c01
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/image/qimage.cpp8
-rw-r--r--src/gui/image/qimage_conversions.cpp14
-rw-r--r--src/gui/image/qimagewriter.cpp6
-rw-r--r--src/gui/kernel/qinputmethod.cpp14
-rw-r--r--src/gui/kernel/qinputmethod.h4
-rw-r--r--src/gui/kernel/qkeysequence.cpp2
-rw-r--r--src/gui/kernel/qkeysequence_p.h3
-rw-r--r--src/gui/kernel/qwindow.cpp11
-rw-r--r--src/gui/opengl/qopengl.h3
-rw-r--r--src/gui/opengl/qopenglcustomshaderstage.cpp1
-rw-r--r--src/gui/opengl/qopenglcustomshaderstage_p.h3
-rw-r--r--src/gui/opengl/qopengltextureglyphcache.cpp171
-rw-r--r--src/gui/painting/qoutlinemapper.cpp21
-rw-r--r--src/gui/painting/qpaintengine.cpp3
-rw-r--r--src/gui/painting/qpainter.cpp21
-rw-r--r--src/gui/painting/qpainter.h1
-rw-r--r--src/gui/painting/qpdf.cpp8
-rw-r--r--src/gui/painting/qregion.cpp10
-rw-r--r--src/gui/painting/qrgba64.h38
-rw-r--r--src/gui/text/qcssparser.cpp1
-rw-r--r--src/gui/text/qcssparser_p.h1
-rw-r--r--src/gui/text/qfontdatabase.cpp4
-rw-r--r--src/gui/text/qfontdatabase.h1
-rw-r--r--src/gui/text/qfontengine_ft.cpp239
-rw-r--r--src/gui/text/qfontengine_ft_p.h13
-rw-r--r--src/gui/text/qrawfont.cpp14
-rw-r--r--src/gui/text/qtextdocument.cpp17
-rw-r--r--src/gui/text/qtextengine_p.h1
-rw-r--r--src/gui/text/qtexthtmlparser.cpp44
-rw-r--r--src/gui/text/qtexthtmlparser_p.h1
-rw-r--r--src/gui/text/qtextobject.cpp7
-rw-r--r--src/gui/text/qzip.cpp9
-rw-r--r--src/gui/util/qgridlayoutengine_p.h1
33 files changed, 490 insertions, 205 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 162a1a20b8..3238d83729 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -2454,10 +2454,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())
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 41b4807671..16789c802e 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -1747,24 +1747,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<QRgb> colorTable = fix_color_table(src->colortable, dest->format);
+ QVector<QRgb> 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<uint *>(dest_data);
const uchar *b = src_data;
uint *end = p + w;
while (p < end)
- *p++ = colorTable.at(qMin<int>(tableSize, *b++));
+ *p++ = colorTablePtr[*b++];
src_data += src->bytes_per_line;
dest_data += dest->bytes_per_line;
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index 1a0bb4d6ff..f3af2738af 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -837,9 +837,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<QImageIOPlugin *>(loader->instance(i));
const int keyCount = keys.size();
for (int k = 0; k < keyCount; ++k) {
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
@@ -183,6 +183,18 @@ QRectF QInputMethod::keyboardRectangle() const
}
/*!
+ \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
remains false.
@@ -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();
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 8a6eeb4cc9..8ccd85795b 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -1643,7 +1643,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 eeea0f5772..116e91c0cd 100644
--- a/src/gui/kernel/qkeysequence_p.h
+++ b/src/gui/kernel/qkeysequence_p.h
@@ -76,7 +76,8 @@ public:
}
inline QKeySequencePrivate(const QKeySequencePrivate &copy) : 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];
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 107ea73a56..81310ae2a2 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -2146,6 +2146,17 @@ bool QWindow::event(QEvent *ev)
break;
}
+ case QEvent::PlatformSurface: {
+ if ((static_cast<QPlatformSurfaceEvent *>(ev))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+#ifndef QT_NO_OPENGL
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ if (context && context->surface() == static_cast<QSurface *>(this))
+ context->doneCurrent();
+#endif
+ }
+ break;
+ }
+
default:
return QObject::event(ev);
}
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 <GLES3/gl3.h>
# else
+# ifndef GL_GLEXT_PROTOTYPES
+# define GL_GLEXT_PROTOTYPES
+# endif
# include <GLES2/gl2.h>
#endif
diff --git a/src/gui/opengl/qopenglcustomshaderstage.cpp b/src/gui/opengl/qopenglcustomshaderstage.cpp
index a0386bd5f3..baa44f86b0 100644
--- a/src/gui/opengl/qopenglcustomshaderstage.cpp
+++ b/src/gui/opengl/qopenglcustomshaderstage.cpp
@@ -69,6 +69,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 099e6aadf8..2342991e5e 100644
--- a/src/gui/opengl/qopenglcustomshaderstage_p.h
+++ b/src/gui/opengl/qopenglcustomshaderstage_p.h
@@ -52,6 +52,7 @@
//
#include <QOpenGLShaderProgram>
+#include <QtGlobal>
QT_BEGIN_NAMESPACE
@@ -78,6 +79,8 @@ protected:
private:
QOpenGLCustomShaderStagePrivate* d_ptr;
+
+ Q_DISABLE_COPY(QOpenGLCustomShaderStage)
};
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; i<c.h; ++i) {
- funcs->glTexSubImage2D(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/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());
}
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.cpp b/src/gui/painting/qpainter.cpp
index e70079915a..aeb76589e0 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -6183,7 +6183,8 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
QString key = QLatin1String("WaveUnderline-")
% pen.color().name()
- % HexString<qreal>(radiusBase);
+ % HexString<qreal>(radiusBase)
+ % HexString<qreal>(pen.widthF());
QPixmap pixmap;
if (QPixmapCache::find(key, pixmap))
@@ -6191,7 +6192,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;
@@ -6214,7 +6215,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);
@@ -6254,9 +6255,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();
@@ -6267,19 +6265,26 @@ 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);
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);
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/qpdf.cpp b/src/gui/painting/qpdf.cpp
index 02f9be197f..b014305796 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -1201,7 +1201,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:
@@ -2214,8 +2214,10 @@ int QPdfEnginePrivate::generateGradientShader(const QGradient *gradient, const Q
case QGradient::RadialGradient:
return generateRadialGradientShader(static_cast<const QRadialGradient *>(gradient), matrix, alpha);
case QGradient::ConicalGradient:
- default:
- qWarning("Implement me!");
+ Q_UNIMPLEMENTED(); // ### Implement me!
+ break;
+ case QGradient::NoGradient:
+ break;
}
return 0;
}
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index abdfc7c8c7..b39a23e7f2 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -1139,7 +1139,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 &region)
{
diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h
index a87d3fbb35..27e1e6e06d 100644
--- a/src/gui/painting/qrgba64.h
+++ b/src/gui/painting/qrgba64.h
@@ -103,7 +103,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
@@ -115,10 +115,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); }
@@ -130,11 +130,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
@@ -143,7 +143,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
@@ -169,18 +169,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
{
@@ -188,10 +188,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));
}
};
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 4782ef5e20..bb92e6bfba 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/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<int> 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/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index 86fb0e8ae4..e89522f5af 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -52,6 +52,7 @@
#include <qscopedvaluerollback.h>
#include "qthreadstorage.h"
#include <qmath.h>
+#include <qendian.h>
#include <ft2build.h>
#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)
@@ -849,11 +879,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,
@@ -893,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);
@@ -1124,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;
@@ -1135,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;
@@ -1169,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<int>(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;
@@ -1239,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
@@ -1561,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;
@@ -1583,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();
@@ -1599,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;
@@ -1642,6 +1743,8 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
if (face)
unlockFace();
+ if (isScalableBitmap())
+ overall = scaledBitmapMetrics(overall);
return overall;
}
@@ -1678,6 +1781,9 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
}
if (face)
unlockFace();
+
+ if (isScalableBitmap())
+ overall = scaledBitmapMetrics(overall);
return overall;
}
@@ -1713,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;
}
@@ -1860,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);
@@ -1881,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 3421c873d5..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);
@@ -140,9 +143,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;
};
@@ -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;
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<QFontEngineMulti *>(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);
}
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 3a08176044..8e4fa8a730 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/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/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<QCss::Declaration>
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;
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index a756549f3e..e2130a09d9 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -418,9 +418,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()
{
diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp
index 5178f5a9a8..7cb89543ba 100644
--- a/src/gui/text/qzip.cpp
+++ b/src/gui/text/qzip.cpp
@@ -822,12 +822,12 @@ void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const
QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode)
{
QScopedPointer<QFile> f(new QFile(archive));
- f->open(mode);
+ const bool result = f->open(mode);
QZipReader::Status status;
const QFileDevice::FileError error = f->error();
- if (error == QFile::NoError)
+ if (result && error == QFile::NoError) {
status = NoError;
- else {
+ } else {
if (error == QFile::ReadError)
status = FileReadError;
else if (error == QFile::OpenError)
@@ -1119,9 +1119,8 @@ void QZipReader::close()
QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode)
{
QScopedPointer<QFile> 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)
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)