summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp18
-rw-r--r--src/gui/graphicsview/qgraphicstransform.cpp21
-rw-r--r--src/gui/gui.pro19
-rw-r--r--src/gui/image/image.pri1
-rw-r--r--src/gui/image/qimage.cpp8
-rw-r--r--src/gui/image/qimage_neon.cpp114
-rw-r--r--src/gui/image/qjpeghandler.cpp11
-rw-r--r--src/gui/kernel/qevent.cpp5
-rw-r--r--src/gui/kernel/qgesture.cpp28
-rw-r--r--src/gui/kernel/qgesturerecognizer.cpp3
-rw-r--r--src/gui/painting/painting.pri21
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp14
-rw-r--r--src/gui/painting/qdrawingprimitive_sse2_p.h8
-rw-r--r--src/gui/text/qtextengine.cpp87
-rw-r--r--src/gui/text/qtextengine_p.h14
-rw-r--r--src/gui/text/qtextlayout.cpp19
16 files changed, 317 insertions, 74 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index e1e27d2..0b3b164 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -7985,6 +7985,24 @@ void QGraphicsItemPrivate::resetHeight()
*/
/*!
+ \property QGraphicsObject::children
+ \since 4.7
+ \internal
+*/
+
+/*!
+ \property QGraphicsObject::width
+ \since 4.7
+ \internal
+*/
+
+/*!
+ \property QGraphicsObject::height
+ \since 4.7
+ \internal
+*/
+
+/*!
\class QAbstractGraphicsShapeItem
\brief The QAbstractGraphicsShapeItem class provides a common base for
all path items.
diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp
index 7b69317..bd3f2ef 100644
--- a/src/gui/graphicsview/qgraphicstransform.cpp
+++ b/src/gui/graphicsview/qgraphicstransform.cpp
@@ -583,6 +583,27 @@ void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const
\sa QGraphicsRotation::axis
*/
+/*!
+ \fn QGraphicsScale::xScaleChanged()
+ \since 4.7
+
+ This signal is emitted whenever the \l xScale property changes.
+*/
+
+/*!
+ \fn QGraphicsScale::yScaleChanged()
+ \since 4.7
+
+ This signal is emitted whenever the \l yScale property changes.
+*/
+
+/*!
+ \fn QGraphicsScale::zScaleChanged()
+ \since 4.7
+
+ This signal is emitted whenever the \l zScale property changes.
+*/
+
#include "moc_qgraphicstransform.cpp"
QT_END_NAMESPACE
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index 28440cc..3943e26 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -77,6 +77,25 @@ symbian {
DEPLOYMENT = partial_upgrade $$DEPLOYMENT
}
+neon:*-g++* {
+ DEFINES += QT_HAVE_NEON
+ QMAKE_CXXFLAGS *= -mfpu=neon
+ HEADERS += $$NEON_HEADERS
+ SOURCES += $$NEON_SOURCES
+
+ DRAWHELPER_NEON_ASM_FILES = $$NEON_ASM
+
+ neon_compiler.commands = $$QMAKE_CXX -c
+ neon_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ neon_compiler.dependency_type = TYPE_C
+ neon_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ neon_compiler.input = DRAWHELPER_NEON_ASM_FILES
+ neon_compiler.variable_out = OBJECTS
+ neon_compiler.name = compiling[neon] ${QMAKE_FILE_IN}
+ silent:neon_compiler.commands = @echo compiling[neon] ${QMAKE_FILE_IN} && $$neon_compiler.commands
+ QMAKE_EXTRA_COMPILERS += neon_compiler
+}
+
contains(QMAKE_MAC_XARCH, no) {
DEFINES += QT_NO_MAC_XARCH
} else {
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index b20a04f..f89706c 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -94,5 +94,6 @@ contains(QT_CONFIG, tiff):include($$PWD/qtiffhandler.pri)
contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri)
# SIMD
+NEON_SOURCES += image/qimage_neon.cpp
SSE2_SOURCES += image/qimage_sse2.cpp
SSSE3_SOURCES += image/qimage_ssse3.cpp
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index cb834c0..ac148ee 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -3769,6 +3769,14 @@ void qInitImageConversions()
converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
}
#endif
+#ifdef QT_HAVE_NEON
+ if (features & NEON) {
+ extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
+ converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon;
+ converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon;
+ converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon;
+ }
+#endif
}
/*!
diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp
new file mode 100644
index 0000000..15bf472
--- /dev/null
+++ b/src/gui/image/qimage_neon.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qimage.h>
+#include <private/qimage_p.h>
+#include <private/qsimd_p.h>
+
+#ifdef QT_HAVE_NEON
+
+QT_BEGIN_NAMESPACE
+
+Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len)
+{
+ if (!len)
+ return;
+
+ const quint32 *const end = dst + len;
+
+ // align dst on 64 bits
+ const int offsetToAlignOn8Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x1;
+ for (int i = 0; i < offsetToAlignOn8Bytes; ++i) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+
+ if ((len - offsetToAlignOn8Bytes) >= 8) {
+ const quint32 *const simdEnd = end - 7;
+ register uint8x8_t fullVector asm ("d3") = vdup_n_u8(0xff);
+ do {
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ asm volatile (
+ "vld3.8 { d4, d5, d6 }, [%[SRC]] !\n\t"
+ "vst4.8 { d3, d4, d5, d6 }, [%[DST],:64] !\n\t"
+ : [DST]"+r" (dst), [SRC]"+r" (src)
+ : "w"(fullVector)
+ : "memory", "d4", "d5", "d6"
+ );
+#else
+ asm volatile (
+ "vld3.8 { d0, d1, d2 }, [%[SRC]] !\n\t"
+ "vswp d0, d2\n\t"
+ "vst4.8 { d0, d1, d2, d3 }, [%[DST],:64] !\n\t"
+ : [DST]"+r" (dst), [SRC]"+r" (src)
+ : "w"(fullVector)
+ : "memory", "d0", "d1", "d2"
+ );
+#endif
+ } while (dst < simdEnd);
+ }
+
+ while (dst != end) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+}
+
+void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGB888);
+ Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const uchar *src_data = (uchar *) src->data;
+ quint32 *dest_data = (quint32 *) dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ qt_convert_rgb888_to_rgb32_neon(dest_data, src_data, src->width);
+ src_data += src->bytes_per_line;
+ dest_data = (quint32 *)((uchar*)dest_data + dest->bytes_per_line);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_NEON
diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp
index d358a5e..eda5efb 100644
--- a/src/gui/image/qjpeghandler.cpp
+++ b/src/gui/image/qjpeghandler.cpp
@@ -803,9 +803,16 @@ bool QJpegHandlerPrivate::read(QImage *image)
QJpegHandler::QJpegHandler()
: d(new QJpegHandlerPrivate(this))
{
-#if defined(QT_HAVE_SSSE3)
const uint features = qDetectCPUFeatures();
-
+ Q_UNUSED(features);
+#if defined(QT_HAVE_NEON)
+ // from qimage_neon.cpp
+ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len);
+
+ if (features & NEON)
+ rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon;
+#endif // QT_HAVE_NEON
+#if defined(QT_HAVE_SSSE3)
// from qimage_ssse3.cpp
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len);
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index bbc9e0b..eade02e 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -4281,6 +4281,11 @@ QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::T
QGestureEvent::accept() for each of them, or an event filter consumes the
event.
+ \section1 Further Reading
+
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
\sa QGesture, QGestureRecognizer,
QWidget::grabGesture(), QGraphicsObject::grabGesture()
*/
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
index 4a4452a..13274c4 100644
--- a/src/gui/kernel/qgesture.cpp
+++ b/src/gui/kernel/qgesture.cpp
@@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE
the QGestureRecognizer object that is registered with the application; see
QGestureRecognizer::registerRecognizer().
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
\section1 Gesture Properties
The class has a list of properties that can be queried by the user to get
@@ -219,7 +222,10 @@ QGesture::GestureCancelPolicy QGesture::gestureCancelPolicy() const
\image pangesture.png
- \sa {Gestures Programming}, QPinchGesture, QSwipeGesture
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
+ \sa QPinchGesture, QSwipeGesture
*/
/*!
@@ -314,6 +320,9 @@ void QPanGesture::setAcceleration(qreal value)
them closer together or further apart to change the scale factor, zoom, or level
of detail of the user interface.
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
\image pinchgesture.png
Instead of repeatedly applying the same pinching gesture, the user may
@@ -322,7 +331,7 @@ void QPanGesture::setAcceleration(qreal value)
will continue to be delivered to the target object, containing an instance
of QPinchGesture in the Qt::GestureUpdated state.
- \sa {Gestures Programming}, QPanGesture, QSwipeGesture
+ \sa QPanGesture, QSwipeGesture
*/
/*!
@@ -572,7 +581,10 @@ void QPinchGesture::setRotationAngle(qreal value)
\image swipegesture.png
- \sa {Gestures Programming}, QPanGesture, QPinchGesture
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
+ \sa QPanGesture, QPinchGesture
*/
/*!
@@ -667,7 +679,10 @@ void QSwipeGesture::setSwipeAngle(qreal value)
\brief The QTapGesture class describes a tap gesture made by the user.
\ingroup gestures
- \sa {Gestures Programming}, QPanGesture, QPinchGesture
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
+ \sa QPanGesture, QPinchGesture
*/
/*!
@@ -700,7 +715,10 @@ void QTapGesture::setPosition(const QPointF &value)
gesture made by the user.
\ingroup gestures
- \sa {Gestures Programming}, QPanGesture, QPinchGesture
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
+ \sa QPanGesture, QPinchGesture
*/
/*!
diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp
index 3e23bbf..e0e7784 100644
--- a/src/gui/kernel/qgesturerecognizer.cpp
+++ b/src/gui/kernel/qgesturerecognizer.cpp
@@ -62,6 +62,9 @@ QT_BEGIN_NAMESPACE
need to use this class directly. Instances will be created behind the scenes by the
framework.
+ For an overview of gesture handling in Qt and information on using gestures
+ in your applications, see the \l{Gestures Programming} document.
+
\section1 Recognizing Gestures
The process of recognizing gestures involves filtering input events sent to specific
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 4023f65..dfa4a48 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -246,23 +246,8 @@ symbian {
QMAKE_CXXFLAGS.ARMCC *= -O3
}
-neon:*-g++* {
- DEFINES += QT_HAVE_NEON
- HEADERS += painting/qdrawhelper_neon_p.h
- SOURCES += painting/qdrawhelper_neon.cpp
- QMAKE_CXXFLAGS *= -mfpu=neon
-
- DRAWHELPER_NEON_ASM_FILES = ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S
-
- neon_compiler.commands = $$QMAKE_CXX -c
- neon_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- neon_compiler.dependency_type = TYPE_C
- neon_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- neon_compiler.input = DRAWHELPER_NEON_ASM_FILES
- neon_compiler.variable_out = OBJECTS
- neon_compiler.name = compiling[neon] ${QMAKE_FILE_IN}
- silent:neon_compiler.commands = @echo compiling[neon] ${QMAKE_FILE_IN} && $$neon_compiler.commands
- QMAKE_EXTRA_COMPILERS += neon_compiler
-}
+NEON_SOURCES += painting/qdrawhelper_neon.cpp
+NEON_HEADERS += painting/qdrawhelper_neon_p.h
+NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S
include($$PWD/../../3rdparty/zlib_dependency.pri)
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 7ab9eda..22c0384 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -112,9 +112,7 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
int x = 0;
// First, align dest to 16 bytes:
- const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;
- const int prologLength = qMin(w, offsetToAlignOn16Bytes);
- for (; x < prologLength; ++x) {
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, w) {
quint32 s = src[x];
s = BYTE_MUL(s, const_alpha);
dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha);
@@ -182,12 +180,10 @@ inline int comp_func_Plus_one_pixel(uint d, const uint s)
void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha)
{
int x = 0;
- const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;
- const int prologLength = qMin(length, offsetToAlignOn16Bytes);
if (const_alpha == 255) {
// 1) Prologue: align destination on 16 bytes
- for (; x < prologLength; ++x)
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
dst[x] = comp_func_Plus_one_pixel(dst[x], src[x]);
// 2) composition with SSE2
@@ -208,7 +204,7 @@ void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uin
const __m128i oneMinusConstAlpha = _mm_set1_epi16(one_minus_const_alpha);
// 1) Prologue: align destination on 16 bytes
- for (; x < prologLength; ++x)
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
dst[x] = comp_func_Plus_one_pixel_const_alpha(dst[x], src[x], const_alpha, one_minus_const_alpha);
const __m128i half = _mm_set1_epi16(0x80);
@@ -239,9 +235,7 @@ void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, u
int x = 0;
// 1) prologue, align on 16 bytes
- const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;
- const int prologLength = qMin(length, offsetToAlignOn16Bytes);
- for (; x < prologLength; ++x)
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], ialpha);
// 2) interpolate pixels with SSE2
diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h
index 18355c2..d8f6bf5 100644
--- a/src/gui/painting/qdrawingprimitive_sse2_p.h
+++ b/src/gui/painting/qdrawingprimitive_sse2_p.h
@@ -143,9 +143,7 @@ QT_BEGIN_NAMESPACE
int x = 0; \
\
/* First, get dst aligned. */ \
- const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;\
- const int prologLength = qMin(length, offsetToAlignOn16Bytes);\
- for (; x < prologLength; ++x) { \
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length) { \
uint s = src[x]; \
if (s >= 0xff000000) \
dst[x] = s; \
@@ -202,9 +200,7 @@ QT_BEGIN_NAMESPACE
{ \
int x = 0; \
\
- const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;\
- const int prologLength = qMin(length, offsetToAlignOn16Bytes);\
- for (; x < prologLength; ++x) { \
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length) { \
quint32 s = src[x]; \
if (s != 0) { \
s = BYTE_MUL(s, const_alpha); \
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 439f2a4..5670e29 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -923,6 +923,13 @@ void QTextEngine::shapeText(int item) const
si.width += glyphs.advances_x[i];
}
+static inline bool hasCaseChange(const QScriptItem &si)
+{
+ return si.analysis.flags == QScriptAnalysis::SmallCaps ||
+ si.analysis.flags == QScriptAnalysis::Uppercase ||
+ si.analysis.flags == QScriptAnalysis::Lowercase;
+}
+
#if defined(Q_WS_WINCE) //TODO
// set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
// and no reordering.
@@ -1050,14 +1057,15 @@ void QTextEngine::shapeTextWithCE(int item) const
if (option.useDesignMetrics())
flags |= DesignMetrics;
- attributes(); // pre-initialize char attributes
+ // pre-initialize char attributes
+ if (! attributes())
+ return;
const int len = length(item);
int num_glyphs = length(item);
const QChar *str = layoutData->string.unicode() + si.position;
ushort upperCased[256];
- if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
- || si.analysis.flags == QScriptAnalysis::Lowercase) {
+ if (hasCaseChange(si)) {
ushort *uc = upperCased;
if (len > 256)
uc = new ushort[len];
@@ -1071,7 +1079,14 @@ void QTextEngine::shapeTextWithCE(int item) const
}
while (true) {
- ensureSpace(num_glyphs);
+ if (! ensureSpace(num_glyphs)) {
+ // If str is converted to uppercase/lowercase form with a new buffer,
+ // we need to delete that buffer before return for error
+ const ushort *uc = reinterpret_cast<const ushort *>(str);
+ if (hasCaseChange(si) && uc != upperCased)
+ delete [] uc;
+ return;
+ }
num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used;
QGlyphLayout g = availableGlyphs(&si);
@@ -1092,9 +1107,7 @@ void QTextEngine::shapeTextWithCE(int item) const
layoutData->used += si.num_glyphs;
const ushort *uc = reinterpret_cast<const ushort *>(str);
- if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
- || si.analysis.flags == QScriptAnalysis::Lowercase)
- && uc != upperCased)
+ if (hasCaseChange(si) && uc != upperCased)
delete [] uc;
}
#endif
@@ -1133,8 +1146,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;
HB_UChar16 upperCased[256]; // XXX what about making this 4096, so we don't have to extend it ever.
- if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
- || si.analysis.flags == QScriptAnalysis::Lowercase) {
+ if (hasCaseChange(si)) {
HB_UChar16 *uc = upperCased;
if (entire_shaper_item.item.length > 256)
uc = new HB_UChar16[entire_shaper_item.item.length];
@@ -1156,17 +1168,24 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics;
entire_shaper_item.num_glyphs = qMax(layoutData->glyphLayout.numGlyphs - layoutData->used, int(entire_shaper_item.item.length));
- ensureSpace(entire_shaper_item.num_glyphs);
+ if (! ensureSpace(entire_shaper_item.num_glyphs)) {
+ if (hasCaseChange(si))
+ delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
+ return;
+ }
QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs);
if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) {
- ensureSpace(entire_shaper_item.num_glyphs);
+ if (! ensureSpace(entire_shaper_item.num_glyphs)) {
+ if (hasCaseChange(si))
+ delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
+ return;
+ }
initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs);
if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) {
// ############ if this happens there's a bug in the fontengine
- if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
- || si.analysis.flags == QScriptAnalysis::Lowercase) && entire_shaper_item.string != upperCased)
+ if (hasCaseChange(si) && entire_shaper_item.string != upperCased)
delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
return;
}
@@ -1231,7 +1250,11 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
remaining_glyphs -= shaper_item.initialGlyphCount;
do {
- ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs);
+ if (! ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs)) {
+ if (hasCaseChange(si))
+ delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
+ return;
+ }
const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos);
moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
@@ -1271,8 +1294,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
layoutData->used += si.num_glyphs;
- if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase)
- && entire_shaper_item.string != upperCased)
+ if (hasCaseChange(si) && entire_shaper_item.string != upperCased)
delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
}
@@ -1317,7 +1339,8 @@ const HB_CharAttributes *QTextEngine::attributes() const
return (HB_CharAttributes *) layoutData->memory;
itemize();
- ensureSpace(layoutData->string.length());
+ if (! ensureSpace(layoutData->string.length()))
+ return NULL;
QVarLengthArray<HB_ScriptItem> hbScriptItems(layoutData->items.size());
@@ -1864,7 +1887,10 @@ void QTextEngine::justify(const QScriptLine &line)
// don't include trailing white spaces when doing justification
int line_length = line.length;
- const HB_CharAttributes *a = attributes()+line.from;
+ const HB_CharAttributes *a = attributes();
+ if (! a)
+ return;
+ a += line.from;
while (line_length && a[line_length-1].whiteSpace)
--line_length;
// subtract one char more, as we can't justfy after the last character
@@ -2045,7 +2071,7 @@ QTextEngine::LayoutData::LayoutData()
memory_on_stack = false;
used = 0;
hasBidi = false;
- inLayout = false;
+ layoutState = LayoutEmpty;
haveCharAttributes = false;
logClustersPtr = 0;
available_glyphs = 0;
@@ -2079,7 +2105,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
}
used = 0;
hasBidi = false;
- inLayout = false;
+ layoutState = LayoutEmpty;
haveCharAttributes = false;
}
@@ -2090,12 +2116,12 @@ QTextEngine::LayoutData::~LayoutData()
memory = 0;
}
-void QTextEngine::LayoutData::reallocate(int totalGlyphs)
+bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
{
Q_ASSERT(totalGlyphs >= glyphLayout.numGlyphs);
if (memory_on_stack && available_glyphs >= totalGlyphs) {
glyphLayout.grow(glyphLayout.data(), totalGlyphs);
- return;
+ return true;
}
int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1;
@@ -2103,7 +2129,14 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs)
int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2;
int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
- Q_ASSERT(newAllocated >= allocated);
+ // These values can be negative if the length of string/glyphs causes overflow,
+ // we can't layout such a long string all at once, so return false here to
+ // indicate there is a failure
+ if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) {
+ layoutState = LayoutFailed;
+ return false;
+ }
+
void **newMem = memory;
newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *));
Q_CHECK_PTR(newMem);
@@ -2124,6 +2157,7 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs)
glyphLayout.grow(reinterpret_cast<char *>(m), totalGlyphs);
allocated = newAllocated;
+ return true;
}
// grow to the new size, copying the existing data to the new layout
@@ -2155,7 +2189,7 @@ void QTextEngine::freeMemory()
} else {
layoutData->used = 0;
layoutData->hasBidi = false;
- layoutData->inLayout = false;
+ layoutData->layoutState = LayoutEmpty;
layoutData->haveCharAttributes = false;
}
for (int i = 0; i < lines.size(); ++i) {
@@ -2314,6 +2348,9 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
shape(i);
HB_CharAttributes *attributes = const_cast<HB_CharAttributes *>(this->attributes());
+ if (!attributes)
+ return QString();
+
unsigned short *logClusters = this->logClusters(&si);
QGlyphLayout glyphs = shapedGlyphs(&si);
@@ -2385,6 +2422,8 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
return QString();
const HB_CharAttributes *attributes = this->attributes();
+ if (!attributes)
+ return QString();
if (mode == Qt::ElideRight) {
QFixed currentWidth;
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index e623fa5..4cbe81f 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -416,6 +416,11 @@ class QTextFormatCollection;
class Q_GUI_EXPORT QTextEngine {
public:
+ enum LayoutState {
+ LayoutEmpty,
+ InLayout,
+ LayoutFailed,
+ };
struct LayoutData {
LayoutData(const QString &str, void **stack_memory, int mem_size);
LayoutData();
@@ -428,11 +433,11 @@ public:
QGlyphLayout glyphLayout;
mutable int used;
uint hasBidi : 1;
- uint inLayout : 1;
+ uint layoutState : 2;
uint memory_on_stack : 1;
bool haveCharAttributes;
QString string;
- void reallocate(int totalGlyphs);
+ bool reallocate(int totalGlyphs);
};
QTextEngine(LayoutData *data);
@@ -520,9 +525,10 @@ public:
return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
}
- inline void ensureSpace(int nGlyphs) const {
+ inline bool ensureSpace(int nGlyphs) const {
if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
- layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
+ return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
+ return true;
}
void freeMemory();
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 674064e..5a11c87 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -74,6 +74,8 @@ static inline QFixed leadingSpaceWidth(QTextEngine *eng, const QScriptLine &line
int pos = line.length;
const HB_CharAttributes *attributes = eng->attributes();
+ if (!attributes)
+ return QFixed();
while (pos > 0 && attributes[line.from + pos - 1].whiteSpace)
--pos;
return eng->width(line.from + pos, line.length - pos);
@@ -601,7 +603,7 @@ bool QTextLayout::cacheEnabled() const
void QTextLayout::beginLayout()
{
#ifndef QT_NO_DEBUG
- if (d->layoutData && d->layoutData->inLayout) {
+ if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
qWarning("QTextLayout::beginLayout: Called while already doing layout");
return;
}
@@ -609,7 +611,7 @@ void QTextLayout::beginLayout()
d->invalidate();
d->clearLineData();
d->itemize();
- d->layoutData->inLayout = true;
+ d->layoutData->layoutState = QTextEngine::InLayout;
}
/*!
@@ -618,7 +620,7 @@ void QTextLayout::beginLayout()
void QTextLayout::endLayout()
{
#ifndef QT_NO_DEBUG
- if (!d->layoutData || !d->layoutData->inLayout) {
+ if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
qWarning("QTextLayout::endLayout: Called without beginLayout()");
return;
}
@@ -627,7 +629,7 @@ void QTextLayout::endLayout()
if (l && d->lines.at(l-1).length < 0) {
QTextLine(l-1, d).setNumColumns(INT_MAX);
}
- d->layoutData->inLayout = false;
+ d->layoutData->layoutState = QTextEngine::LayoutEmpty;
if (!d->cacheGlyphs)
d->freeMemory();
}
@@ -757,11 +759,14 @@ bool QTextLayout::isValidCursorPosition(int pos) const
QTextLine QTextLayout::createLine()
{
#ifndef QT_NO_DEBUG
- if (!d->layoutData || !d->layoutData->inLayout) {
+ if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
qWarning("QTextLayout::createLine: Called without layouting");
return QTextLine();
}
#endif
+ if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
+ return QTextLine();
+
int l = d->lines.size();
if (l && d->lines.at(l-1).length < 0) {
QTextLine(l-1, d).setNumColumns(INT_MAX);
@@ -1801,6 +1806,8 @@ void QTextLine::layout_helper(int maxGlyphs)
Qt::Alignment alignment = eng->option.alignment();
const HB_CharAttributes *attributes = eng->attributes();
+ if (!attributes)
+ return;
lbh.currentPosition = line.from;
int end = 0;
lbh.logClusters = eng->layoutData->logClustersPtr;
@@ -1814,6 +1821,8 @@ void QTextLine::layout_helper(int maxGlyphs)
if (!current.num_glyphs) {
eng->shape(item);
attributes = eng->attributes();
+ if (!attributes)
+ return;
lbh.logClusters = eng->layoutData->logClustersPtr;
}
lbh.currentPosition = qMax(line.from, current.position);