Merge "Merge remote-tracking branch 'origin/5.5' into dev" into refs/staging/dev

This commit is contained in:
Liang Qi 2015-04-09 06:35:26 +00:00 committed by The Qt Project
commit 65fdde30d0
32 changed files with 437 additions and 314 deletions

11
configure vendored
View File

@ -561,21 +561,28 @@ fi
# initalize variables # initalize variables
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
SYSTEM_VARIABLES="RANLIB STRIP OBJDUMP LD CC CXX CFLAGS CXXFLAGS LDFLAGS" SYSTEM_VARIABLES="AR RANLIB STRIP OBJDUMP LD CC CXX CFLAGS CXXFLAGS LDFLAGS"
for varname in $SYSTEM_VARIABLES; do for varname in $SYSTEM_VARIABLES; do
qmakevarname="${varname}" qmakevarname="${varname}"
qmakecmdargs=""
# use LDFLAGS for autoconf compat, but qmake uses QMAKE_LFLAGS # use LDFLAGS for autoconf compat, but qmake uses QMAKE_LFLAGS
if [ "${varname}" = "LDFLAGS" ]; then if [ "${varname}" = "LDFLAGS" ]; then
qmakevarname="LFLAGS" qmakevarname="LFLAGS"
elif [ "${varname}" = "LD" ]; then elif [ "${varname}" = "LD" ]; then
qmakevarname="LINK" qmakevarname="LINK"
elif [ "${varname}" = "AR" ]; then
# QMAKE_AR needs to be set to "/path/to/ar cqs" but the
# environment variable will be set to the command only so we
# need to append " cqs" for autoconf compatibility
qmakecmdargs=" cqs"
fi fi
cmd=`echo \ cmd=`echo \
'if [ -n "\$'${varname}'" ]; then 'if [ -n "\$'${varname}'" ]; then
QMakeVar set QMAKE_'${qmakevarname}' "\$'${varname}'" QMakeVar set QMAKE_'${qmakevarname}' "\$'${varname}${qmakecmdargs}'"
fi'` fi'`
eval "$cmd" eval "$cmd"
done done
# Use CC/CXX to run config.tests # Use CC/CXX to run config.tests
mkdir -p "$outpath/config.tests" mkdir -p "$outpath/config.tests"
rm -f "$outpath/config.tests/.qmake.cache" rm -f "$outpath/config.tests/.qmake.cache"

View File

@ -4,10 +4,8 @@ CONFIG *= thread
win32 { win32 {
contains(QT_CONFIG, shared) { contains(QT_CONFIG, shared) {
# this variable is read by qmake in qmake/generators/win32/msvc_vcproj.cpp # this variable is read by qmake in qmake/generators/win32/msvc_vcproj.cpp
# function VcprojGenerator::initDeploymentTool(), which contains some hardcoded # function VcprojGenerator::initDeploymentTool()
# library names (the ones that were static in Qt 4) QMAKE_DLL_PATHS += $$[QT_INSTALL_BINS/get]
# it probably doesn't work anymore and should not be in this file
QMAKE_QT_DLL = 1
} }
} }
CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG

View File

@ -1267,31 +1267,43 @@ void VcprojGenerator::initDeploymentTool()
if (targetPath.endsWith("/") || targetPath.endsWith("\\")) if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
targetPath.chop(1); targetPath.chop(1);
} }
ProStringList dllPaths = project->values("QMAKE_DLL_PATHS");
// Only deploy Qt libs for shared build // Only deploy Qt libs for shared build
if (!project->values("QMAKE_QT_DLL").isEmpty()) { if (!dllPaths.isEmpty()) {
// FIXME: This code should actually resolve the libraries from all Qt modules. // FIXME: This code should actually resolve the libraries from all Qt modules.
const QString &qtdir = project->propertyValue(ProKey("QT_INSTALL_LIBS/get")).toQString();
ProStringList arg = project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE"); ProStringList arg = project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE");
for (ProStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) { for (ProStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) {
if (it->contains(qtdir)) { QString dllName = (*it).toQString();
QString dllName = (*it).toQString(); dllName.replace(QLatin1Char('\\'), QLatin1Char('/'));
// LIBPATH isn't relevant for deployment
if (dllName.startsWith(QLatin1String("/LIBPATH:")))
continue;
// We want to deploy .dlls not .libs
if (dllName.endsWith(QLatin1String(".lib")))
dllName.replace(dllName.length() - 3, 3, QLatin1String("dll"));
// Use only the file name and check in Qt's install path and LIBPATHs to check for existence
dllName.remove(0, dllName.lastIndexOf(QLatin1Char('/')) + 1);
QFileInfo info;
foreach (const ProString &dllPath, dllPaths) {
QString absoluteDllFilePath = dllPath.toQString();
if (!absoluteDllFilePath.endsWith(QLatin1Char('/')))
absoluteDllFilePath += QLatin1Char('/');
absoluteDllFilePath += dllName;
info = QFileInfo(absoluteDllFilePath);
if (info.exists())
break;
}
if (dllName.contains(QLatin1String("QAxContainer")) if (!info.exists())
|| dllName.contains(QLatin1String("qtmain")) continue;
|| dllName.contains(QLatin1String("QtUiTools"))) if (conf.WinRT) {
continue; QString absoluteFilePath(QDir::toNativeSeparators(info.absoluteFilePath()));
dllName.replace(QLatin1String(".lib") , QLatin1String(".dll")); vcProject.DeploymentFiles.addFile(absoluteFilePath);
QFileInfo info(dllName); } else {
if (conf.WinRT) { conf.deployment.AdditionalFiles += info.fileName()
QString absoluteFilePath(QDir::toNativeSeparators(info.absoluteFilePath())); + "|" + QDir::toNativeSeparators(info.absolutePath())
vcProject.DeploymentFiles.addFile(absoluteFilePath); + "|" + targetPath
} else { + "|0;";
conf.deployment.AdditionalFiles += info.fileName()
+ "|" + QDir::toNativeSeparators(info.absolutePath())
+ "|" + targetPath
+ "|0;";
}
} }
} }
} }

View File

@ -49,26 +49,35 @@
applications: applications:
\list \list
\li \l {Concurrent Map and Map-Reduce}
\list
\li \l {QtConcurrent::map}{QtConcurrent::map()} applies a function
to every item in a container, modifying the items in-place.
\li \l {QtConcurrent::mapped}{QtConcurrent::mapped()} is like
map(), except that it returns a new container with the
modifications.
\li \l {QtConcurrent::mappedReduced}{QtConcurrent::mappedReduced()}
is like mapped(), except that the modified results are reduced
or folded into a single result.
\endlist
\li \l {QtConcurrent::map}{QtConcurrent::map()} applies a function to every item in a container, \li \l {Concurrent Filter and Filter-Reduce}
modifying the items in-place. \list
\li \l {QtConcurrent::filter}{QtConcurrent::filter()} removes all items
from a container based on the result of a filter function.
\li \l {QtConcurrent::filtered}{QtConcurrent::filtered()} is like
filter(), except that it returns a new container with the filtered
results.
\li \l {QtConcurrent::filteredReduced}{QtConcurrent::filteredReduced()}
is like filtered(), except that the filtered results are reduced or
folded into a single result.
\endlist
\li \l {QtConcurrent::mapped}{QtConcurrent::mapped()} is like map(), except that it returns a new \li \l {Concurrent Run}
container with the modifications. \list
\li \l {QtConcurrent::run}{QtConcurrent::run()} runs a function in
\li \l {QtConcurrent::mappedReduced}{QtConcurrent::mappedReduced()} is like mapped(), except that the another thread.
modified results are reduced or folded into a single result. \endlist
\li \l {QtConcurrent::filter}{QtConcurrent::filter()} removes all items from a container based on the
result of a filter function.
\li \l {QtConcurrent::filtered}{QtConcurrent::filtered()} is like filter(), except that it returns a new
container with the filtered results.
\li \l {QtConcurrent::filteredReduced}{QtConcurrent::filteredReduced()} is like filtered(), except that the
filtered results are reduced or folded into a single result.
\li \l {QtConcurrent::run}{QtConcurrent::run()} runs a function in another thread.
\li QFuture represents the result of an asynchronous computation. \li QFuture represents the result of an asynchronous computation.

View File

@ -179,6 +179,8 @@
Calls \a filterFunction once for each item in \a sequence. If Calls \a filterFunction once for each item in \a sequence. If
\a filterFunction returns \c true, the item is kept in \a sequence; \a filterFunction returns \c true, the item is kept in \a sequence;
otherwise, the item is removed from \a sequence. otherwise, the item is removed from \a sequence.
\sa {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -188,6 +190,8 @@
new Sequence of kept items. If \a filterFunction returns \c true, a copy of new Sequence of kept items. If \a filterFunction returns \c true, a copy of
the item is put in the new Sequence. Otherwise, the item will \e not the item is put in the new Sequence. Otherwise, the item will \e not
appear in the new Sequence. appear in the new Sequence.
\sa {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -197,6 +201,8 @@
returns a new Sequence of kept items. If \a filterFunction returns \c true, a returns a new Sequence of kept items. If \a filterFunction returns \c true, a
copy of the item is put in the new Sequence. Otherwise, the item will copy of the item is put in the new Sequence. Otherwise, the item will
\e not appear in the new Sequence. \e not appear in the new Sequence.
\sa {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -213,6 +219,8 @@
QtConcurrent::UnorderedReduce. If \a reduceOptions is QtConcurrent::UnorderedReduce. If \a reduceOptions is
QtConcurrent::OrderedReduce, \a reduceFunction is called in the order of QtConcurrent::OrderedReduce, \a reduceFunction is called in the order of
the original sequence. the original sequence.
\sa {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -229,6 +237,8 @@
QtConcurrent::UnorderedReduce. If \a reduceOptions is QtConcurrent::UnorderedReduce. If \a reduceOptions is
QtConcurrent::OrderedReduce, the \a reduceFunction is called in the order QtConcurrent::OrderedReduce, the \a reduceFunction is called in the order
of the original sequence. of the original sequence.
\sa {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -239,6 +249,8 @@
otherwise, the item is removed from \a sequence. otherwise, the item is removed from \a sequence.
\note This function will block until all items in the sequence have been processed. \note This function will block until all items in the sequence have been processed.
\sa {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -251,7 +263,7 @@
\note This function will block until all items in the sequence have been processed. \note This function will block until all items in the sequence have been processed.
\sa filtered() \sa filtered(), {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -265,7 +277,7 @@
\note This function will block until the iterator reaches the end of the \note This function will block until the iterator reaches the end of the
sequence being processed. sequence being processed.
\sa filtered() \sa filtered(), {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -285,7 +297,7 @@
\note This function will block until all items in the sequence have been processed. \note This function will block until all items in the sequence have been processed.
\sa filteredReduced() \sa filteredReduced(), {Concurrent Filter and Filter-Reduce}
*/ */
/*! /*!
@ -306,5 +318,5 @@
\note This function will block until the iterator reaches the end of the \note This function will block until the iterator reaches the end of the
sequence being processed. sequence being processed.
\sa filteredReduced() \sa filteredReduced(), {Concurrent Filter and Filter-Reduce}
*/ */

View File

@ -229,6 +229,8 @@
Calls \a function once for each item in \a sequence. The \a function is Calls \a function once for each item in \a sequence. The \a function is
passed a reference to the item, so that any modifications done to the item passed a reference to the item, so that any modifications done to the item
will appear in \a sequence. will appear in \a sequence.
\sa {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -237,6 +239,8 @@
Calls \a function once for each item from \a begin to \a end. The Calls \a function once for each item from \a begin to \a end. The
\a function is passed a reference to the item, so that any modifications \a function is passed a reference to the item, so that any modifications
done to the item will appear in the sequence which the iterators belong to. done to the item will appear in the sequence which the iterators belong to.
\sa {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -245,6 +249,8 @@
Calls \a function once for each item in \a sequence and returns a future Calls \a function once for each item in \a sequence and returns a future
with each mapped item as a result. You can use QFuture::const_iterator or with each mapped item as a result. You can use QFuture::const_iterator or
QFutureIterator to iterate through the results. QFutureIterator to iterate through the results.
\sa {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -253,6 +259,8 @@
Calls \a function once for each item from \a begin to \a end and returns a Calls \a function once for each item from \a begin to \a end and returns a
future with each mapped item as a result. You can use future with each mapped item as a result. You can use
QFuture::const_iterator or QFutureIterator to iterate through the results. QFuture::const_iterator or QFutureIterator to iterate through the results.
\sa {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -266,6 +274,8 @@
Note that while \a mapFunction is called concurrently, only one thread at a Note that while \a mapFunction is called concurrently, only one thread at a
time will call \a reduceFunction. The order in which \a reduceFunction is time will call \a reduceFunction. The order in which \a reduceFunction is
called is determined by \a reduceOptions. called is determined by \a reduceOptions.
\sa {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -281,6 +291,8 @@
\a reduceFunction is called is undefined. \a reduceFunction is called is undefined.
\note QtConcurrent::OrderedReduce results in the ordered reduction. \note QtConcurrent::OrderedReduce results in the ordered reduction.
\sa {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -292,7 +304,7 @@
\note This function will block until all items in the sequence have been processed. \note This function will block until all items in the sequence have been processed.
\sa map() \sa map(), {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -305,7 +317,7 @@
\note This function will block until the iterator reaches the end of the \note This function will block until the iterator reaches the end of the
sequence being processed. sequence being processed.
\sa map() \sa map(), {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -316,7 +328,7 @@
\note This function will block until all items in the sequence have been processed. \note This function will block until all items in the sequence have been processed.
\sa mapped() \sa mapped(), {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -333,7 +345,7 @@
\note This function will block until the iterator reaches the end of the \note This function will block until the iterator reaches the end of the
sequence being processed. sequence being processed.
\sa mapped() \sa mapped(), {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -348,7 +360,7 @@
\note This function will block until all items in the sequence have been processed. \note This function will block until all items in the sequence have been processed.
\sa mapped() \sa mapped(), {Concurrent Map and Map-Reduce}
*/ */
/*! /*!
@ -364,5 +376,5 @@
\note This function will block until the iterator reaches the end of the \note This function will block until the iterator reaches the end of the
sequence being processed. sequence being processed.
\sa blockingMappedReduced() \sa blockingMappedReduced(), {Concurrent Map and Map-Reduce}
*/ */

View File

@ -143,6 +143,8 @@
canceling, pausing, or progress reporting. The QFuture returned can only canceling, pausing, or progress reporting. The QFuture returned can only
be used to query for the running/finished status and the return value of be used to query for the running/finished status and the return value of
the function. the function.
\sa {Concurrent Run}
*/ */
/*! /*!
@ -160,4 +162,6 @@
canceling, pausing, or progress reporting. The QFuture returned can only canceling, pausing, or progress reporting. The QFuture returned can only
be used to query for the running/finished status and the return value of be used to query for the running/finished status and the return value of
the function. the function.
\sa {Concurrent Run}
*/ */

View File

@ -299,18 +299,6 @@ static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environm
if (environment.isEmpty()) if (environment.isEmpty())
return 0; return 0;
// if LD_LIBRARY_PATH exists in the current environment, but
// not in the environment list passed by the programmer, then
// copy it over.
#if defined(Q_OS_MAC)
static const char libraryPath[] = "DYLD_LIBRARY_PATH";
#else
static const char libraryPath[] = "LD_LIBRARY_PATH";
#endif
const QByteArray envLibraryPath = qgetenv(libraryPath);
bool needToAddLibraryPath = !envLibraryPath.isEmpty() &&
!environment.contains(QProcessEnvironmentPrivate::Key(QByteArray(libraryPath)));
char **envp = new char *[environment.count() + 2]; char **envp = new char *[environment.count() + 2];
envp[environment.count()] = 0; envp[environment.count()] = 0;
envp[environment.count() + 1] = 0; envp[environment.count() + 1] = 0;
@ -327,9 +315,6 @@ static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environm
envp[(*envc)++] = ::strdup(key.constData()); envp[(*envc)++] = ::strdup(key.constData());
} }
if (needToAddLibraryPath)
envp[(*envc)++] = ::strdup(QByteArray(QByteArray(libraryPath) + '=' +
envLibraryPath).constData());
return envp; return envp;
} }

View File

@ -215,7 +215,7 @@ bool QSaveFile::open(OpenMode mode)
d->finalFileName = existingFile.filePath(); d->finalFileName = existingFile.filePath();
} }
d->fileEngine = new QTemporaryFileEngine(d->finalFileName); d->fileEngine = new QTemporaryFileEngine(d->finalFileName, 0666);
// Same as in QFile: QIODevice provides the buffering, so there's no need to request it from the file engine. // Same as in QFile: QIODevice provides the buffering, so there's no need to request it from the file engine.
if (!d->fileEngine->open(mode | QIODevice::Unbuffered)) { if (!d->fileEngine->open(mode | QIODevice::Unbuffered)) {
QFileDevice::FileError err = d->fileEngine->error(); QFileDevice::FileError err = d->fileEngine->error();

View File

@ -103,13 +103,14 @@ typedef int NativeFileHandle;
\a path is used as a template when generating unique paths, \a pos \a path is used as a template when generating unique paths, \a pos
identifies the position of the first character that will be replaced in the identifies the position of the first character that will be replaced in the
template and \a length the number of characters that may be substituted. template and \a length the number of characters that may be substituted.
\a mode specifies the file mode bits (not used on Windows).
Returns an open handle to the newly created file if successful, an invalid Returns an open handle to the newly created file if successful, an invalid
handle otherwise. In both cases, the string in \a path will be changed and handle otherwise. In both cases, the string in \a path will be changed and
contain the generated path name. contain the generated path name.
*/ */
static bool createFileFromTemplate(NativeFileHandle &file, static bool createFileFromTemplate(NativeFileHandle &file,
QFileSystemEntry::NativePath &path, size_t pos, size_t length, QFileSystemEntry::NativePath &path, size_t pos, size_t length, quint32 mode,
QSystemError &error) QSystemError &error)
{ {
Q_ASSERT(length != 0); Q_ASSERT(length != 0);
@ -143,6 +144,8 @@ static bool createFileFromTemplate(NativeFileHandle &file,
for (;;) { for (;;) {
// Atomically create file and obtain handle // Atomically create file and obtain handle
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
Q_UNUSED(mode);
# ifndef Q_OS_WINRT # ifndef Q_OS_WINRT
file = CreateFile((const wchar_t *)path.constData(), file = CreateFile((const wchar_t *)path.constData(),
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
@ -175,7 +178,7 @@ static bool createFileFromTemplate(NativeFileHandle &file,
#else // POSIX #else // POSIX
file = QT_OPEN(path.constData(), file = QT_OPEN(path.constData(),
QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE,
0600); static_cast<mode_t>(mode));
if (file != -1) if (file != -1)
return true; return true;
@ -333,7 +336,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
NativeFileHandle &file = d->fd; NativeFileHandle &file = d->fd;
#endif #endif
if (!createFileFromTemplate(file, filename, phPos, phLength, error)) { if (!createFileFromTemplate(file, filename, phPos, phLength, fileMode, error)) {
setError(QFile::OpenError, error.toString()); setError(QFile::OpenError, error.toString());
return false; return false;
} }
@ -407,9 +410,9 @@ QAbstractFileEngine *QTemporaryFilePrivate::engine() const
{ {
if (!fileEngine) { if (!fileEngine) {
if (fileName.isEmpty()) if (fileName.isEmpty())
fileEngine = new QTemporaryFileEngine(templateName); fileEngine = new QTemporaryFileEngine(templateName, 0600);
else else
fileEngine = new QTemporaryFileEngine(fileName, false); fileEngine = new QTemporaryFileEngine(fileName, 0600, false);
} }
return fileEngine; return fileEngine;
} }

View File

@ -77,8 +77,13 @@ class QTemporaryFileEngine : public QFSFileEngine
{ {
Q_DECLARE_PRIVATE(QFSFileEngine) Q_DECLARE_PRIVATE(QFSFileEngine)
public: public:
QTemporaryFileEngine(const QString &file, bool fileIsTemplate = true)
: QFSFileEngine(), filePathIsTemplate(fileIsTemplate), QTemporaryFileEngine(const QString &file,
quint32 fileMode,
bool fileIsTemplate = true) :
QFSFileEngine(),
fileMode(fileMode),
filePathIsTemplate(fileIsTemplate),
filePathWasTemplate(fileIsTemplate) filePathWasTemplate(fileIsTemplate)
{ {
Q_D(QFSFileEngine); Q_D(QFSFileEngine);
@ -100,6 +105,7 @@ public:
bool renameOverwrite(const QString &newName); bool renameOverwrite(const QString &newName);
bool close(); bool close();
quint32 fileMode;
bool filePathIsTemplate; bool filePathIsTemplate;
bool filePathWasTemplate; bool filePathWasTemplate;
}; };

View File

@ -38,10 +38,8 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#if defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && !defined(Q_CC_INTEL) QT_WARNING_PUSH
#pragma GCC diagnostic push QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
const QArrayData QArrayData::shared_null[2] = { const QArrayData QArrayData::shared_null[2] = {
{ Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared null { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared null
@ -52,9 +50,7 @@ static const QArrayData qt_array[3] = {
{ { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, sizeof(QArrayData) }, // unsharable empty { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, sizeof(QArrayData) }, // unsharable empty
/* zero initialized terminator */}; /* zero initialized terminator */};
#if defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && !defined(Q_CC_INTEL) QT_WARNING_POP
#pragma GCC diagnostic pop
#endif
static const QArrayData &qt_array_empty = qt_array[0]; static const QArrayData &qt_array_empty = qt_array[0];
static const QArrayData &qt_array_unsharable_empty = qt_array[1]; static const QArrayData &qt_array_unsharable_empty = qt_array[1];

View File

@ -869,44 +869,62 @@ static inline char qToLower(char c)
/*! \fn QByteArray::iterator QByteArray::begin() /*! \fn QByteArray::iterator QByteArray::begin()
\internal Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in
the byte-array.
\sa constBegin(), end()
*/ */
/*! \fn QByteArray::const_iterator QByteArray::begin() const /*! \fn QByteArray::const_iterator QByteArray::begin() const
\internal \overload begin()
*/ */
/*! \fn QByteArray::const_iterator QByteArray::cbegin() const /*! \fn QByteArray::const_iterator QByteArray::cbegin() const
\since 5.0 \since 5.0
\internal Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character
in the byte-array.
\sa begin(), cend()
*/ */
/*! \fn QByteArray::const_iterator QByteArray::constBegin() const /*! \fn QByteArray::const_iterator QByteArray::constBegin() const
\internal Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character
in the byte-array.
\sa begin(), constEnd()
*/ */
/*! \fn QByteArray::iterator QByteArray::end() /*! \fn QByteArray::iterator QByteArray::end()
\internal Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character
after the last character in the byte-array.
\sa begin(), constEnd()
*/ */
/*! \fn QByteArray::const_iterator QByteArray::end() const /*! \fn QByteArray::const_iterator QByteArray::end() const
\internal \overload end()
*/ */
/*! \fn QByteArray::const_iterator QByteArray::cend() const /*! \fn QByteArray::const_iterator QByteArray::cend() const
\since 5.0 \since 5.0
\internal Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
character after the last character in the list.
\sa cbegin(), end()
*/ */
/*! \fn QByteArray::const_iterator QByteArray::constEnd() const /*! \fn QByteArray::const_iterator QByteArray::constEnd() const
\internal Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
character after the last character in the list.
\sa constBegin(), end()
*/ */
/*! \fn void QByteArray::push_back(const QByteArray &other) /*! \fn void QByteArray::push_back(const QByteArray &other)

View File

@ -3237,7 +3237,6 @@ bool QDateTime::isDaylightTime() const
void QDateTime::setDate(const QDate &date) void QDateTime::setDate(const QDate &date)
{ {
detach();
d->setDateTime(date, time()); d->setDateTime(date, time());
} }
@ -3256,7 +3255,6 @@ void QDateTime::setDate(const QDate &date)
void QDateTime::setTime(const QTime &time) void QDateTime::setTime(const QTime &time)
{ {
detach();
d->setDateTime(date(), time); d->setDateTime(date(), time);
} }
@ -3278,7 +3276,7 @@ void QDateTime::setTime(const QTime &time)
void QDateTime::setTimeSpec(Qt::TimeSpec spec) void QDateTime::setTimeSpec(Qt::TimeSpec spec)
{ {
detach(); QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
d->setTimeSpec(spec, 0); d->setTimeSpec(spec, 0);
d->checkValidDateTime(); d->checkValidDateTime();
} }
@ -3300,7 +3298,7 @@ void QDateTime::setTimeSpec(Qt::TimeSpec spec)
void QDateTime::setOffsetFromUtc(int offsetSeconds) void QDateTime::setOffsetFromUtc(int offsetSeconds)
{ {
detach(); QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
d->setTimeSpec(Qt::OffsetFromUTC, offsetSeconds); d->setTimeSpec(Qt::OffsetFromUTC, offsetSeconds);
d->checkValidDateTime(); d->checkValidDateTime();
} }
@ -3319,7 +3317,7 @@ void QDateTime::setOffsetFromUtc(int offsetSeconds)
void QDateTime::setTimeZone(const QTimeZone &toZone) void QDateTime::setTimeZone(const QTimeZone &toZone)
{ {
detach(); QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
d->m_spec = Qt::TimeZone; d->m_spec = Qt::TimeZone;
d->m_offsetFromUtc = 0; d->m_offsetFromUtc = 0;
d->m_timeZone = toZone; d->m_timeZone = toZone;
@ -3395,7 +3393,7 @@ uint QDateTime::toTime_t() const
*/ */
void QDateTime::setMSecsSinceEpoch(qint64 msecs) void QDateTime::setMSecsSinceEpoch(qint64 msecs)
{ {
detach(); QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
d->m_status = 0; d->m_status = 0;
switch (d->m_spec) { switch (d->m_spec) {
@ -3669,7 +3667,6 @@ QString QDateTime::toString(const QString& format) const
QDateTime QDateTime::addDays(qint64 ndays) const QDateTime QDateTime::addDays(qint64 ndays) const
{ {
QDateTime dt(*this); QDateTime dt(*this);
dt.detach();
QPair<QDate, QTime> p = d->getDateTime(); QPair<QDate, QTime> p = d->getDateTime();
QDate &date = p.first; QDate &date = p.first;
QTime &time = p.second; QTime &time = p.second;
@ -3705,7 +3702,6 @@ QDateTime QDateTime::addDays(qint64 ndays) const
QDateTime QDateTime::addMonths(int nmonths) const QDateTime QDateTime::addMonths(int nmonths) const
{ {
QDateTime dt(*this); QDateTime dt(*this);
dt.detach();
QPair<QDate, QTime> p = d->getDateTime(); QPair<QDate, QTime> p = d->getDateTime();
QDate &date = p.first; QDate &date = p.first;
QTime &time = p.second; QTime &time = p.second;
@ -3741,7 +3737,6 @@ QDateTime QDateTime::addMonths(int nmonths) const
QDateTime QDateTime::addYears(int nyears) const QDateTime QDateTime::addYears(int nyears) const
{ {
QDateTime dt(*this); QDateTime dt(*this);
dt.detach();
QPair<QDate, QTime> p = d->getDateTime(); QPair<QDate, QTime> p = d->getDateTime();
QDate &date = p.first; QDate &date = p.first;
QTime &time = p.second; QTime &time = p.second;
@ -3790,7 +3785,6 @@ QDateTime QDateTime::addMSecs(qint64 msecs) const
return QDateTime(); return QDateTime();
QDateTime dt(*this); QDateTime dt(*this);
dt.detach();
if (d->m_spec == Qt::LocalTime || d->m_spec == Qt::TimeZone) if (d->m_spec == Qt::LocalTime || d->m_spec == Qt::TimeZone)
// Convert to real UTC first in case crosses daylight transition // Convert to real UTC first in case crosses daylight transition
dt.setMSecsSinceEpoch(d->toMSecsSinceEpoch() + msecs); dt.setMSecsSinceEpoch(d->toMSecsSinceEpoch() + msecs);
@ -4267,7 +4261,6 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds) QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
{ {
QDateTime dt; QDateTime dt;
dt.detach();
dt.d->setTimeSpec(spec, offsetSeconds); dt.d->setTimeSpec(spec, offsetSeconds);
dt.setMSecsSinceEpoch(msecs); dt.setMSecsSinceEpoch(msecs);
return dt; return dt;
@ -4687,14 +4680,6 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
\sa toTimeSpec() \sa toTimeSpec()
*/ */
/*!
\internal
*/
void QDateTime::detach()
{
d.detach();
}
/***************************************************************************** /*****************************************************************************
Date/time stream functions Date/time stream functions
*****************************************************************************/ *****************************************************************************/
@ -4846,8 +4831,6 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
QDataStream &operator>>(QDataStream &in, QDateTime &dateTime) QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
{ {
dateTime.detach();
QDate dt; QDate dt;
QTime tm; QTime tm;
qint8 ts = 0; qint8 ts = 0;

View File

@ -321,7 +321,6 @@ public:
private: private:
friend class QDateTimePrivate; friend class QDateTimePrivate;
void detach();
// ### Qt6: Using a private here has high impact on runtime // ### Qt6: Using a private here has high impact on runtime
// on users such as QFileInfo. In Qt 6, the data members // on users such as QFileInfo. In Qt 6, the data members

View File

@ -46,6 +46,11 @@ public:
inline QQueue() {} inline QQueue() {}
inline ~QQueue() {} inline ~QQueue() {}
inline void swap(QQueue<T> &other) { QList<T>::swap(other); } // prevent QList<->QQueue swaps inline void swap(QQueue<T> &other) { QList<T>::swap(other); } // prevent QList<->QQueue swaps
#ifndef Q_QDOC
// bring in QList::swap(int, int). We cannot say using QList<T>::swap,
// because we don't want to make swap(QList&) available.
inline void swap(int i, int j) { QList<T>::swap(i, j); }
#endif
inline void enqueue(const T &t) { QList<T>::append(t); } inline void enqueue(const T &t) { QList<T>::append(t); }
inline T dequeue() { return QList<T>::takeFirst(); } inline T dequeue() { return QList<T>::takeFirst(); }
inline T &head() { return QList<T>::first(); } inline T &head() { return QList<T>::first(); }

View File

@ -1291,7 +1291,7 @@ const QString::Null QString::null = { };
\since 5.0 \since 5.0
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the list. character after the last character in the list.
\sa cbegin(), end() \sa cbegin(), end()
*/ */
@ -1299,7 +1299,7 @@ const QString::Null QString::null = { };
/*! \fn QString::const_iterator QString::constEnd() const /*! \fn QString::const_iterator QString::constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the list. character after the last character in the list.
\sa constBegin(), end() \sa constBegin(), end()
*/ */

View File

@ -717,11 +717,41 @@ QQuaternion QQuaternion::fromAxes(const QVector3D &xAxis, const QVector3D &yAxis
return QQuaternion::fromRotationMatrix(rot3x3); return QQuaternion::fromRotationMatrix(rot3x3);
} }
/*!
\since 5.5
Constructs the quaternion using specified forward direction \a direction
and upward direction \a up.
If the upward direction was not specified or the forward and upward
vectors are collinear, a new orthonormal upward direction will be generated.
\sa fromAxes(), rotationTo()
*/
QQuaternion QQuaternion::fromDirection(const QVector3D &direction, const QVector3D &up)
{
if (qFuzzyIsNull(direction.x()) && qFuzzyIsNull(direction.y()) && qFuzzyIsNull(direction.z()))
return QQuaternion();
const QVector3D zAxis(direction.normalized());
QVector3D xAxis(QVector3D::crossProduct(up, zAxis));
if (qFuzzyIsNull(xAxis.lengthSquared())) {
// collinear or invalid up vector; derive shortest arc to new direction
return QQuaternion::rotationTo(QVector3D(0.0f, 0.0f, 1.0f), zAxis);
}
xAxis.normalize();
const QVector3D yAxis(QVector3D::crossProduct(zAxis, xAxis));
return QQuaternion::fromAxes(xAxis, yAxis, zAxis);
}
/*! /*!
\since 5.5 \since 5.5
Returns the shortest arc quaternion to rotate from the direction described by the vector \a from Returns the shortest arc quaternion to rotate from the direction described by the vector \a from
to the direction described by the vector \a to. to the direction described by the vector \a to.
\sa fromDirection()
*/ */
QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to) QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
{ {

View File

@ -138,6 +138,8 @@ public:
void getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const; void getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const;
static QQuaternion fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis); static QQuaternion fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis);
static QQuaternion fromDirection(const QVector3D &direction, const QVector3D &up);
static QQuaternion rotationTo(const QVector3D &from, const QVector3D &to); static QQuaternion rotationTo(const QVector3D &from, const QVector3D &to);
#endif #endif

View File

@ -1484,8 +1484,10 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
const int ty0 = targetRect.top(); const int ty0 = targetRect.top();
const int ty1 = targetRect.top() + targetRect.height(); const int ty1 = targetRect.top() + targetRect.height();
extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0); const GLuint defaultFboId = ctx->defaultFramebufferObject();
extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0);
extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);
extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);
extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1, extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
tx0, ty0, tx1, ty1, tx0, ty0, tx1, ty1,

View File

@ -123,17 +123,6 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition))) if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
continue; continue;
// This is a rather crude hack, but it works.
// The FreeType font engine is not capable of getting precise metrics for the alphamap
// without first rasterizing the glyph. If we force the glyph to be rasterized before
// we ask for the alphaMapBoundingBox(), the glyph will be loaded, rasterized and its
// proper metrics will be cached and used later.
if (fontEngine->hasInternalCaching()) {
QImage *locked = fontEngine->lockedAlphaMapForGlyph(glyph, subPixelPosition, m_format);
if (locked && !locked->isNull())
fontEngine->unlockAlphaMapForGlyph();
}
glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format); glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format);
#ifdef CACHE_DEBUG #ifdef CACHE_DEBUG

View File

@ -43,6 +43,7 @@
#include "qfile.h" #include "qfile.h"
#include "qfileinfo.h" #include "qfileinfo.h"
#include <qscopedvaluerollback.h>
#include "qthreadstorage.h" #include "qthreadstorage.h"
#include <qmath.h> #include <qmath.h>
@ -800,6 +801,17 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
return load_flags; return load_flags;
} }
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;
}
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
QFixed subPixelPosition, QFixed subPixelPosition,
GlyphFormat format, GlyphFormat format,
@ -807,13 +819,9 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
{ {
// Q_ASSERT(freetype->lock == 1); // Q_ASSERT(freetype->lock == 1);
if (format == Format_None) { if (format == Format_None)
if (defaultFormat != Format_None) { format = defaultFormat != Format_None ? defaultFormat : Format_Mono;
format = defaultFormat; Q_ASSERT(format != Format_None);
} else {
format = Format_Mono;
}
}
Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0; Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
if (g && g->format == format && (fetchMetricsOnly || g->data)) if (g && g->format == format && (fetchMetricsOnly || g->data))
@ -822,32 +830,28 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
if (!g && set && set->isGlyphMissing(glyph)) if (!g && set && set->isGlyphMissing(glyph))
return &emptyGlyph; return &emptyGlyph;
QFontEngineFT::GlyphInfo info;
Q_ASSERT(format != Format_None); FT_Face face = freetype->face;
FT_Matrix matrix = freetype->matrix;
FT_Vector v;
v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.value());
v.y = 0;
FT_Set_Transform(face, &matrix, &v);
bool hsubpixel = false; bool hsubpixel = false;
int vfactor = 1; int vfactor = 1;
int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor); int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
if (format != Format_Mono && !embeddedbitmap)
load_flags |= FT_LOAD_NO_BITMAP;
FT_Matrix matrix = freetype->matrix;
bool transform = matrix.xx != 0x10000 bool transform = matrix.xx != 0x10000
|| matrix.yy != 0x10000 || matrix.yy != 0x10000
|| matrix.xy != 0 || matrix.xy != 0
|| matrix.yx != 0; || matrix.yx != 0;
if (transform) if (transform || (format != Format_Mono && !embeddedbitmap))
load_flags |= FT_LOAD_NO_BITMAP; load_flags |= FT_LOAD_NO_BITMAP;
FT_Face face = freetype->face;
FT_Vector v;
v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
v.y = 0;
FT_Set_Transform(face, &freetype->matrix, &v);
FT_Error err = FT_Load_Glyph(face, glyph, load_flags); FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
if (err && (load_flags & FT_LOAD_NO_BITMAP)) { if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
load_flags &= ~FT_LOAD_NO_BITMAP; load_flags &= ~FT_LOAD_NO_BITMAP;
@ -891,6 +895,8 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
FT_Matrix_Multiply(&m, &matrix); FT_Matrix_Multiply(&m, &matrix);
} }
GlyphInfo info;
info.linearAdvance = slot->linearHoriAdvance >> 10;
info.xOff = TRUNC(ROUND(slot->advance.x)); info.xOff = TRUNC(ROUND(slot->advance.x));
info.yOff = 0; info.yOff = 0;
@ -899,27 +905,23 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width); int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
int top = CEIL(slot->metrics.horiBearingY); int top = CEIL(slot->metrics.horiBearingY);
int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height); int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
int width = right-left; info.x = TRUNC(left);
int height = top-bottom; info.y = TRUNC(top);
info.width = TRUNC(right - left);
info.height = TRUNC(top - bottom);
// If any of the metrics are too large to fit, don't cache them // If any of the metrics are too large to fit, don't cache them
if (qAbs(info.xOff) >= 128 if (areMetricsTooLarge(info))
|| qAbs(TRUNC(top)) >= 128
|| TRUNC(width) >= 256
|| TRUNC(height) >= 256
|| qAbs(TRUNC(left)) >= 128
|| qAbs(TRUNC(ROUND(slot->advance.x))) >= 128) {
return 0; return 0;
}
g = new Glyph; g = new Glyph;
g->data = 0; g->data = 0;
g->linearAdvance = slot->linearHoriAdvance >> 10; g->linearAdvance = info.linearAdvance;
g->width = TRUNC(width); g->width = info.width;
g->height = TRUNC(height); g->height = info.height;
g->x = TRUNC(left); g->x = info.x;
g->y = TRUNC(top); g->y = info.y;
g->advance = TRUNC(ROUND(slot->advance.x)); g->advance = info.xOff;
g->format = format; g->format = format;
if (set) if (set)
@ -948,7 +950,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
info.height = slot->bitmap.rows / vfactor; info.height = slot->bitmap.rows / vfactor;
info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width; info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
info.x = -slot->bitmap_left; info.x = slot->bitmap_left;
info.y = slot->bitmap_top; info.y = slot->bitmap_top;
glyph_buffer_size = info.width * info.height * 4; glyph_buffer_size = info.width * info.height * 4;
@ -1013,23 +1015,16 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
hpixels = hpixels*3 + 8; hpixels = hpixels*3 + 8;
info.width = hpixels; info.width = hpixels;
info.height = TRUNC(top - bottom); info.height = TRUNC(top - bottom);
info.x = -TRUNC(left); info.x = TRUNC(left);
info.y = TRUNC(top); info.y = TRUNC(top);
if (hsubpixel) { if (hsubpixel) {
info.width /= 3; info.width /= 3;
info.x += 1; info.x -= 1;
} }
bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10) // If any of the metrics are too large to fit, don't cache them
|| ((uchar)(info.width) != info.width) if (areMetricsTooLarge(info))
|| ((uchar)(info.height) != info.height)
|| ((signed char)(info.x) != info.x)
|| ((signed char)(info.y) != info.y)
|| ((signed char)(info.xOff) != info.xOff));
if (large_glyph) {
return 0; return 0;
}
int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 : int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
(format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4)); (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
@ -1142,10 +1137,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
g->data = 0; g->data = 0;
} }
g->linearAdvance = slot->linearHoriAdvance >> 10; g->linearAdvance = info.linearAdvance;
g->width = info.width; g->width = info.width;
g->height = info.height; g->height = info.height;
g->x = -info.x; g->x = info.x;
g->y = info.y; g->y = info.y;
g->advance = info.xOff; g->advance = info.xOff;
g->format = format; g->format = format;
@ -1725,12 +1720,38 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
return overall; return overall;
} }
static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat)
{
if (glyph == Q_NULLPTR)
return QImage();
QImage::Format format;
int bytesPerLine;
switch (glyphFormat) {
case QFontEngine::Format_Mono:
format = QImage::Format_Mono;
bytesPerLine = ((glyph->width + 31) & ~31) >> 3;
break;
case QFontEngine::Format_A8:
format = QImage::Format_Alpha8;
bytesPerLine = (glyph->width + 3) & ~3;
break;
case QFontEngine::Format_A32:
format = QImage::Format_ARGB32;
bytesPerLine = glyph->width * 4;
break;
default:
Q_UNREACHABLE();
};
return QImage(static_cast<const uchar *>(glyph->data), glyph->width, glyph->height, bytesPerLine, format);
}
QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition, QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
QFontEngine::GlyphFormat neededFormat, QFontEngine::GlyphFormat neededFormat,
const QTransform &t, QPoint *offset) const QTransform &t, QPoint *offset)
{ {
Q_ASSERT(currentlyLockedAlphaMap.isNull()); Q_ASSERT(currentlyLockedAlphaMap.isNull());
lockFace();
if (isBitmapFont()) if (isBitmapFont())
neededFormat = Format_Mono; neededFormat = Format_Mono;
@ -1739,86 +1760,20 @@ QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixe
else if (neededFormat == Format_None) else if (neededFormat == Format_None)
neededFormat = Format_A8; neededFormat = Format_A8;
QImage::Format format; Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t);
switch (neededFormat) {
case Format_Mono:
format = QImage::Format_Mono;
break;
case Format_A8:
format = QImage::Format_Alpha8;
break;
case Format_A32:
format = QImage::Format_ARGB32;
break;
default:
Q_ASSERT(false);
format = QImage::Format_Invalid;
};
QFontEngineFT::Glyph *glyph; if (offset != 0 && glyph != 0)
if (cacheEnabled) {
QGlyphSet *gset = loadGlyphSet(t);
QFontEngine::HintStyle hintStyle = default_hint_style;
if (t.type() >= QTransform::TxScale) {
// disable hinting if the glyphs are transformed
default_hint_style = HintNone;
}
if (gset) {
FT_Matrix m = matrix;
FT_Matrix_Multiply(&gset->transformationMatrix, &m);
FT_Set_Transform(freetype->face, &m, 0);
freetype->matrix = m;
}
if (!gset || gset->outline_drawing || !(glyph = loadGlyph(gset, glyphIndex, subPixelPosition,
neededFormat))) {
default_hint_style = hintStyle;
return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
offset);
}
default_hint_style = hintStyle;
} else {
FT_Matrix m = matrix;
FT_Matrix extra = QTransformToFTMatrix(t);
FT_Matrix_Multiply(&extra, &m);
FT_Set_Transform(freetype->face, &m, 0);
freetype->matrix = m;
glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
}
if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph;
unlockFace();
return 0;
}
int pitch;
switch (neededFormat) {
case Format_Mono:
pitch = ((glyph->width + 31) & ~31) >> 3;
break;
case Format_A8:
pitch = (glyph->width + 3) & ~3;
break;
case Format_A32:
pitch = glyph->width * 4;
break;
default:
Q_ASSERT(false);
pitch = 0;
};
if (offset != 0)
*offset = QPoint(glyph->x, -glyph->y); *offset = QPoint(glyph->x, -glyph->y);
currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format); currentlyLockedAlphaMap = alphaMapFromGlyphData(glyph, neededFormat);
if (!cacheEnabled && glyph != &emptyGlyph) { if (!cacheEnabled && glyph != &emptyGlyph) {
currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy(); currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy();
delete glyph; delete glyph;
} }
Q_ASSERT(!currentlyLockedAlphaMap.isNull());
if (currentlyLockedAlphaMap.isNull())
return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t, offset);
QImageData *data = currentlyLockedAlphaMap.data_ptr(); QImageData *data = currentlyLockedAlphaMap.data_ptr();
data->is_locked = true; data->is_locked = true;
@ -1828,9 +1783,7 @@ QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixe
void QFontEngineFT::unlockAlphaMapForGlyph() void QFontEngineFT::unlockAlphaMapForGlyph()
{ {
Q_ASSERT(!currentlyLockedAlphaMap.isNull()); QFontEngine::unlockAlphaMapForGlyph();
unlockFace();
currentlyLockedAlphaMap = QImage();
} }
QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
@ -1845,6 +1798,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
Glyph *glyph = glyphSet != 0 ? glyphSet->getGlyph(g, subPixelPosition) : 0; Glyph *glyph = glyphSet != 0 ? glyphSet->getGlyph(g, subPixelPosition) : 0;
if (!glyph || glyph->format != format || (!fetchBoundingBox && !glyph->data)) { if (!glyph || glyph->format != format || (!fetchBoundingBox && !glyph->data)) {
QScopedValueRollback<HintStyle> saved_default_hint_style(default_hint_style);
if (t.type() >= QTransform::TxScale)
default_hint_style = HintNone; // disable hinting if the glyphs are transformed
lockFace(); lockFace();
FT_Matrix m = this->matrix; FT_Matrix m = this->matrix;
FT_Matrix ftMatrix = glyphSet != 0 ? glyphSet->transformationMatrix : QTransformToFTMatrix(t); FT_Matrix ftMatrix = glyphSet != 0 ? glyphSet->transformationMatrix : QTransformToFTMatrix(t);
@ -1864,32 +1821,20 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
{ {
Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono, t); const GlyphFormat neededFormat = antialias ? Format_A8 : Format_Mono;
if (!glyph || !glyph->data) {
if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph;
return QFontEngine::alphaMapForGlyph(g);
}
const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4; Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t);
QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Alpha8 : QImage::Format_Mono); QImage img = alphaMapFromGlyphData(glyph, neededFormat);
if (!antialias) { img = img.copy();
QVector<QRgb> colors(2);
colors[0] = qRgba(0, 0, 0, 0);
colors[1] = qRgba(0, 0, 0, 255);
img.setColorTable(colors);
}
Q_ASSERT(img.bytesPerLine() == pitch);
if (glyph->width) {
for (int y = 0; y < glyph->height; ++y)
memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
}
if (!cacheEnabled && glyph != &emptyGlyph) if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph; delete glyph;
return img; if (!img.isNull())
return img;
return QFontEngine::alphaMapForGlyph(g);
} }
QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
@ -1897,20 +1842,20 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, co
if (t.type() > QTransform::TxRotate) if (t.type() > QTransform::TxRotate)
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32, t); const GlyphFormat neededFormat = Format_A32;
if (!glyph || !glyph->data) {
if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph;
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
}
QImage img(glyph->width, glyph->height, QImage::Format_RGB32); Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t);
memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
QImage img = alphaMapFromGlyphData(glyph, neededFormat);
img = img.copy();
if (!cacheEnabled && glyph != &emptyGlyph) if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph; delete glyph;
return img; if (!img.isNull())
return img;
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
} }
void QFontEngineFT::removeGlyphFromCache(glyph_t glyph) void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)

View File

@ -143,6 +143,7 @@ public:
}; };
struct GlyphInfo { struct GlyphInfo {
int linearAdvance;
unsigned short width; unsigned short width;
unsigned short height; unsigned short height;
short x; short x;

View File

@ -1265,8 +1265,8 @@ bool QAbstractSocketPrivate::readFromSocket()
bytesToRead = readBufferMaxSize - buffer.size(); bytesToRead = readBufferMaxSize - buffer.size();
#if defined(QABSTRACTSOCKET_DEBUG) #if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::readFromSocket() about to read %d bytes", qDebug("QAbstractSocketPrivate::readFromSocket() about to read %lld bytes",
int(bytesToRead)); bytesToRead);
#endif #endif
// Read from the socket, store data in the read buffer. // Read from the socket, store data in the read buffer.
@ -1277,10 +1277,10 @@ bool QAbstractSocketPrivate::readFromSocket()
buffer.chop(bytesToRead); buffer.chop(bytesToRead);
return true; return true;
} }
buffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes))); buffer.chop(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes));
#if defined(QABSTRACTSOCKET_DEBUG) #if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::readFromSocket() got %d bytes, buffer size = %d", qDebug("QAbstractSocketPrivate::readFromSocket() got %lld bytes, buffer size = %lld",
int(readBytes), buffer.size()); readBytes, buffer.size());
#endif #endif
if (!socketEngine->isValid()) { if (!socketEngine->isValid()) {
@ -1726,7 +1726,7 @@ qint64 QAbstractSocket::bytesAvailable() const
available += d->socketEngine->bytesAvailable(); available += d->socketEngine->bytesAvailable();
#if defined(QABSTRACTSOCKET_DEBUG) #if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::bytesAvailable() == %llu", available); qDebug("QAbstractSocket::bytesAvailable() == %lld", available);
#endif #endif
return available; return available;
} }
@ -1805,8 +1805,8 @@ bool QAbstractSocket::canReadLine() const
{ {
bool hasLine = d_func()->buffer.canReadLine(); bool hasLine = d_func()->buffer.canReadLine();
#if defined (QABSTRACTSOCKET_DEBUG) #if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::canReadLine() == %s, buffer size = %d, size = %d", hasLine ? "true" : "false", qDebug("QAbstractSocket::canReadLine() == %s, buffer size = %lld, size = %lld",
d_func()->buffer.size(), d_func()->buffer.size()); hasLine ? "true" : "false", d_func()->buffer.size(), d_func()->buffer.size());
#endif #endif
return hasLine || QIODevice::canReadLine(); return hasLine || QIODevice::canReadLine();
} }

View File

@ -303,8 +303,7 @@ namespace {
, m_referenceCount(0) , m_referenceCount(0)
{ {
} }
virtual ~DirectWriteFontFileStream()
~DirectWriteFontFileStream()
{ {
} }
@ -355,7 +354,7 @@ namespace {
OUT void **fragmentContext) OUT void **fragmentContext)
{ {
*fragmentContext = NULL; *fragmentContext = NULL;
if (fragmentSize + fileOffset <= m_fontData.size()) { if (fileOffset + fragmentSize <= quint64(m_fontData.size())) {
*fragmentStart = m_fontData.data() + fileOffset; *fragmentStart = m_fontData.data() + fileOffset;
return S_OK; return S_OK;
} else { } else {
@ -384,8 +383,7 @@ namespace {
{ {
public: public:
DirectWriteFontFileLoader() : m_referenceCount(0) {} DirectWriteFontFileLoader() : m_referenceCount(0) {}
virtual ~DirectWriteFontFileLoader()
~DirectWriteFontFileLoader()
{ {
} }
@ -1104,18 +1102,14 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal
GUID guid; GUID guid;
CoCreateGuid(&guid); CoCreateGuid(&guid);
#ifdef Q_CC_GNU QT_WARNING_PUSH
# pragma GCC diagnostic push QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
QString uniqueFamilyName = QLatin1Char('f') QString uniqueFamilyName = QLatin1Char('f')
+ QString::number(guid.Data1, 36) + QLatin1Char('-') + QString::number(guid.Data1, 36) + QLatin1Char('-')
+ QString::number(guid.Data2, 36) + QLatin1Char('-') + QString::number(guid.Data2, 36) + QLatin1Char('-')
+ QString::number(guid.Data3, 36) + QLatin1Char('-') + QString::number(guid.Data3, 36) + QLatin1Char('-')
+ QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36); + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
#ifdef Q_CC_GNU QT_WARNING_POP
# pragma GCC diagnostic pop
#endif
QString actualFontName = font.changeFamilyName(uniqueFamilyName); QString actualFontName = font.changeFamilyName(uniqueFamilyName);
if (actualFontName.isEmpty()) { if (actualFontName.isEmpty()) {

View File

@ -33,6 +33,10 @@
#ifndef QT_NO_DIRECTWRITE #ifndef QT_NO_DIRECTWRITE
#if WINVER < 0x0600
# undef WINVER
# define WINVER 0x0600
#endif
#if _WIN32_WINNT < 0x0600 #if _WIN32_WINNT < 0x0600
#undef _WIN32_WINNT #undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 #define _WIN32_WINNT 0x0600
@ -61,10 +65,14 @@ namespace {
class GeometrySink: public IDWriteGeometrySink class GeometrySink: public IDWriteGeometrySink
{ {
public: public:
GeometrySink(QPainterPath *path) : m_path(path), m_refCount(0) GeometrySink(QPainterPath *path)
: m_refCount(0), m_path(path)
{ {
Q_ASSERT(m_path != 0); Q_ASSERT(m_path != 0);
} }
virtual ~GeometrySink()
{
}
IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount); IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount);
IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount); IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount);

View File

@ -39,14 +39,12 @@
# define DC_COLLATE 22 # define DC_COLLATE 22
#endif #endif
#if defined (Q_CC_MINGW)
# pragma GCC diagnostic ignored "-Wsign-compare"
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#ifndef QT_NO_PRINTER #ifndef QT_NO_PRINTER
QT_WARNING_DISABLE_GCC("-Wsign-compare")
extern qreal qt_pointMultiplier(QPageLayout::Unit unit); extern qreal qt_pointMultiplier(QPageLayout::Unit unit);
static inline uint qwcsnlen(const wchar_t *str, uint maxlen) static inline uint qwcsnlen(const wchar_t *str, uint maxlen)

View File

@ -58,8 +58,9 @@
- (NSString *)nameForLegacyLogging; - (NSString *)nameForLegacyLogging;
@end @end
#pragma GCC diagnostic push // Ignore XCTestProbe deprecation QT_WARNING_PUSH
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // Ignore XCTestProbe deprecation
QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
// --------------------------------------------------------- // ---------------------------------------------------------
@ -498,4 +499,4 @@ bool QXcodeTestLogger::isActive()
return s_currentTestLogger; return s_currentTestLogger;
} }
#pragma GCC diagnostic pop QT_WARNING_POP

View File

@ -149,7 +149,7 @@ QString Node::plainFullName(const Node* relative) const
*/ */
QString Node::fullName(const Node* relative) const QString Node::fullName(const Node* relative) const
{ {
if (isDocumentNode()) if ((isDocumentNode() || isGroup()) && !title().isEmpty())
return title(); return title();
return plainFullName(relative); return plainFullName(relative);
} }

View File

@ -2036,6 +2036,8 @@ void QTabBar::wheelEvent(QWheelEvent *event)
int offset = event->delta() > 0 ? -1 : 1; int offset = event->delta() > 0 ? -1 : 1;
d->setCurrentNextEnabledIndex(offset); d->setCurrentNextEnabledIndex(offset);
QWidget::wheelEvent(event); QWidget::wheelEvent(event);
#else
Q_UNUSED(event)
#endif #endif
} }
#endif //QT_NO_WHEELEVENT #endif //QT_NO_WHEELEVENT

View File

@ -119,6 +119,14 @@ void tst_QSaveFile::transactionalWrite()
QFile reader(targetFile); QFile reader(targetFile);
QVERIFY(reader.open(QIODevice::ReadOnly)); QVERIFY(reader.open(QIODevice::ReadOnly));
QCOMPARE(QString::fromLatin1(reader.readAll()), QString::fromLatin1("Hello")); QCOMPARE(QString::fromLatin1(reader.readAll()), QString::fromLatin1("Hello"));
// check that permissions are the same as for QFile
const QString otherFile = dir.path() + QString::fromLatin1("/otherfile");
QFile::remove(otherFile);
QFile other(otherFile);
other.open(QIODevice::WriteOnly);
other.close();
QCOMPARE(QFile::permissions(targetFile), QFile::permissions(otherFile));
} }
void tst_QSaveFile::saveTwice() void tst_QSaveFile::saveTwice()

View File

@ -141,6 +141,9 @@ private slots:
void rotationTo_data(); void rotationTo_data();
void rotationTo(); void rotationTo();
void fromDirection_data();
void fromDirection();
void fromEulerAngles_data(); void fromEulerAngles_data();
void fromEulerAngles(); void fromEulerAngles();
@ -989,6 +992,97 @@ void tst_QQuaternion::rotationTo()
QVERIFY(myFuzzyCompare(vec2, from)); QVERIFY(myFuzzyCompare(vec2, from));
} }
static QByteArray testnameForAxis(const QVector3D &axis)
{
QByteArray testname;
if (axis == QVector3D()) {
testname = "null";
} else {
if (axis.x()) {
testname += axis.x() < 0 ? "-" : "+";
testname += "X";
}
if (axis.y()) {
testname += axis.y() < 0 ? "-" : "+";
testname += "Y";
}
if (axis.z()) {
testname += axis.z() < 0 ? "-" : "+";
testname += "Z";
}
}
return testname;
}
// Test quaternion convertion to and from orthonormal axes.
void tst_QQuaternion::fromDirection_data()
{
QTest::addColumn<QVector3D>("direction");
QTest::addColumn<QVector3D>("up");
QList<QQuaternion> orientations;
orientations << QQuaternion();
for (int angle = 45; angle <= 360; angle += 45) {
orientations << QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), angle)
<< QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), angle)
<< QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle)
<< QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), angle)
* QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), angle)
* QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle);
}
// othonormal up and dir
foreach (const QQuaternion &q, orientations) {
QVector3D xAxis, yAxis, zAxis;
q.getAxes(&xAxis, &yAxis, &zAxis);
QTest::newRow("dir: " + testnameForAxis(zAxis) + ", up: " + testnameForAxis(yAxis))
<< zAxis * 10.0f << yAxis * 10.0f;
}
// collinear up and dir
QTest::newRow("dir: +X, up: +X") << QVector3D(10.0f, 0.0f, 0.0f) << QVector3D(10.0f, 0.0f, 0.0f);
QTest::newRow("dir: +X, up: -X") << QVector3D(10.0f, 0.0f, 0.0f) << QVector3D(-10.0f, 0.0f, 0.0f);
QTest::newRow("dir: +Y, up: +Y") << QVector3D(0.0f, 10.0f, 0.0f) << QVector3D(0.0f, 10.0f, 0.0f);
QTest::newRow("dir: +Y, up: -Y") << QVector3D(0.0f, 10.0f, 0.0f) << QVector3D(0.0f, -10.0f, 0.0f);
QTest::newRow("dir: +Z, up: +Z") << QVector3D(0.0f, 0.0f, 10.0f) << QVector3D(0.0f, 0.0f, 10.0f);
QTest::newRow("dir: +Z, up: -Z") << QVector3D(0.0f, 0.0f, 10.0f) << QVector3D(0.0f, 0.0f, -10.0f);
QTest::newRow("dir: +X+Y+Z, up: +X+Y+Z") << QVector3D(10.0f, 10.0f, 10.0f) << QVector3D(10.0f, 10.0f, 10.0f);
QTest::newRow("dir: +X+Y+Z, up: -X-Y-Z") << QVector3D(10.0f, 10.0f, 10.0f) << QVector3D(-10.0f, -10.0f, -10.0f);
// invalid up
foreach (const QQuaternion &q, orientations) {
QVector3D xAxis, yAxis, zAxis;
q.getAxes(&xAxis, &yAxis, &zAxis);
QTest::newRow("dir: " + testnameForAxis(zAxis) + ", up: null")
<< zAxis * 10.0f << QVector3D();
}
}
void tst_QQuaternion::fromDirection()
{
QFETCH(QVector3D, direction);
QFETCH(QVector3D, up);
QVector3D expextedZ(direction != QVector3D() ? direction.normalized() : QVector3D(0, 0, 1));
QVector3D expextedY(up.normalized());
QQuaternion result = QQuaternion::fromDirection(direction, up);
QVERIFY(myFuzzyCompare(result, result.normalized()));
QVector3D xAxis, yAxis, zAxis;
result.getAxes(&xAxis, &yAxis, &zAxis);
QVERIFY(myFuzzyCompare(zAxis, expextedZ));
if (!qFuzzyIsNull(QVector3D::crossProduct(expextedZ, expextedY).lengthSquared())) {
QVector3D expextedX(QVector3D::crossProduct(expextedY, expextedZ));
QVERIFY(myFuzzyCompare(yAxis, expextedY));
QVERIFY(myFuzzyCompare(xAxis, expextedX));
}
}
// Test quaternion creation from an axis and an angle. // Test quaternion creation from an axis and an angle.
void tst_QQuaternion::fromEulerAngles_data() void tst_QQuaternion::fromEulerAngles_data()
{ {