Merge remote-tracking branch 'origin/5.9' into dev
Change-Id: I0ec164ce6e8099e6e4d6b40a3c7340737473ef4b
This commit is contained in:
commit
12e82111ab
|
@ -57,9 +57,18 @@ void BirthdayParty::setHost(Person *c)
|
|||
|
||||
QQmlListProperty<Person> BirthdayParty::guests()
|
||||
{
|
||||
return QQmlListProperty<Person>(this, m_guests);
|
||||
return QQmlListProperty<Person>(this, this,
|
||||
&BirthdayParty::appendGuest,
|
||||
&BirthdayParty::guestCount,
|
||||
&BirthdayParty::guest,
|
||||
&BirthdayParty::clearGuests);
|
||||
}
|
||||
|
||||
void BirthdayParty::appendGuest(Person* p) {
|
||||
m_guests.append(p);
|
||||
}
|
||||
|
||||
|
||||
int BirthdayParty::guestCount() const
|
||||
{
|
||||
return m_guests.count();
|
||||
|
@ -69,5 +78,25 @@ Person *BirthdayParty::guest(int index) const
|
|||
{
|
||||
return m_guests.at(index);
|
||||
}
|
||||
|
||||
void BirthdayParty::clearGuests() {
|
||||
return m_guests.clear();
|
||||
}
|
||||
|
||||
// ![0]
|
||||
|
||||
void BirthdayParty::appendGuest(QQmlListProperty<Person>* list, Person* p) {
|
||||
reinterpret_cast< BirthdayParty* >(list->data)->appendGuest(p);
|
||||
}
|
||||
|
||||
void BirthdayParty::clearGuests(QQmlListProperty<Person>* list) {
|
||||
reinterpret_cast< BirthdayParty* >(list->data)->clearGuests();
|
||||
}
|
||||
|
||||
Person* BirthdayParty::guest(QQmlListProperty<Person>* list, int i) {
|
||||
return reinterpret_cast< BirthdayParty* >(list->data)->guest(i);
|
||||
}
|
||||
|
||||
int BirthdayParty::guestCount(QQmlListProperty<Person>* list) {
|
||||
return reinterpret_cast< BirthdayParty* >(list->data)->guestCount();
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#define BIRTHDAYPARTY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QQmlListProperty>
|
||||
#include "person.h"
|
||||
|
||||
|
@ -63,12 +64,19 @@ public:
|
|||
void setHost(Person *);
|
||||
|
||||
QQmlListProperty<Person> guests();
|
||||
void appendGuest(Person*);
|
||||
int guestCount() const;
|
||||
Person *guest(int) const;
|
||||
void clearGuests();
|
||||
|
||||
private:
|
||||
static void appendGuest(QQmlListProperty<Person>*, Person*);
|
||||
static int guestCount(QQmlListProperty<Person>*);
|
||||
static Person* guest(QQmlListProperty<Person>*, int);
|
||||
static void clearGuests(QQmlListProperty<Person>*);
|
||||
|
||||
Person *m_host;
|
||||
QList<Person *> m_guests;
|
||||
QVector<Person *> m_guests;
|
||||
};
|
||||
// ![3]
|
||||
|
||||
|
|
|
@ -253,6 +253,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
#if defined(V4_BOOTSTRAP)
|
||||
template <typename LabelType>
|
||||
class Jump {
|
||||
template<class TemplateAssemblerType>
|
||||
|
@ -291,6 +292,7 @@ public:
|
|||
private:
|
||||
AssemblerLabel m_label;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Stack operations:
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ qtHaveModule(quick) {
|
|||
sharedimage \
|
||||
testlib
|
||||
|
||||
qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
|
||||
qtConfig(quick-shadereffect):qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
|
||||
SUBDIRS += particles
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,12 @@ void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal)
|
|||
QMutexLocker locker(&m_lock);
|
||||
|
||||
if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) {
|
||||
m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext));
|
||||
if (QV4::ExecutionContext *parentContext
|
||||
= m_engine->parentContext(m_engine->currentContext)) {
|
||||
m_currentContext.set(m_engine, *parentContext);
|
||||
} else {
|
||||
m_currentContext.clear();
|
||||
}
|
||||
m_stepping = StepOver;
|
||||
m_returnedValue.set(m_engine, retVal);
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ void QSGOpenVGFontGlyphCache::populate(const QVector<quint32> &glyphs)
|
|||
referencedGlyphs.insert(glyphIndex);
|
||||
|
||||
|
||||
if (!m_cachedGlyphs.contains(glyphIndex)) {
|
||||
if (!m_glyphReferences.contains(glyphIndex)) {
|
||||
newGlyphs.insert(glyphIndex);
|
||||
}
|
||||
}
|
||||
|
@ -119,17 +119,9 @@ void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet<quint32> &glyphs)
|
|||
{
|
||||
VGfloat origin[2];
|
||||
VGfloat escapement[2];
|
||||
QRectF metrics;
|
||||
QRawFont rawFont = m_referenceFont;
|
||||
|
||||
// Before adding any new glyphs, remove any unused glyphs
|
||||
for (auto glyph : qAsConst(m_unusedGlyphs)) {
|
||||
vgClearGlyph(m_font, glyph);
|
||||
}
|
||||
|
||||
for (auto glyph : glyphs) {
|
||||
m_cachedGlyphs.insert(glyph);
|
||||
|
||||
// Calculate the path for the glyph and cache it.
|
||||
QPainterPath path = rawFont.pathForGlyph(glyph);
|
||||
VGPath vgPath;
|
||||
|
@ -151,12 +143,23 @@ void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet<quint32> &glyphs)
|
|||
|
||||
void QSGOpenVGFontGlyphCache::referenceGlyphs(const QSet<quint32> &glyphs)
|
||||
{
|
||||
m_unusedGlyphs -= glyphs;
|
||||
for (auto glyph : glyphs) {
|
||||
if (m_glyphReferences.contains(glyph))
|
||||
m_glyphReferences[glyph] += 1;
|
||||
else
|
||||
m_glyphReferences.insert(glyph, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void QSGOpenVGFontGlyphCache::releaseGlyphs(const QSet<quint32> &glyphs)
|
||||
{
|
||||
m_unusedGlyphs += glyphs;
|
||||
for (auto glyph : glyphs) {
|
||||
int references = m_glyphReferences[glyph] -= 1;
|
||||
if (references == 0) {
|
||||
vgClearGlyph(m_font, glyph);
|
||||
m_glyphReferences.remove(glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -87,8 +87,7 @@ private:
|
|||
int m_glyphCount;
|
||||
|
||||
VGFont m_font;
|
||||
QSet<quint32> m_cachedGlyphs;
|
||||
QSet<quint32> m_unusedGlyphs;
|
||||
QHash<quint32, int> m_glyphReferences;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2116,7 +2116,8 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
|
|||
|
||||
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
|
||||
object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
|
||||
|
||||
object->flags = serializedObject->flags;
|
||||
object->id = serializedObject->id;
|
||||
object->location = serializedObject->location;
|
||||
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
|
||||
|
||||
|
@ -2175,6 +2176,15 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
|
|||
object->properties->append(p);
|
||||
}
|
||||
|
||||
{
|
||||
const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable();
|
||||
for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) {
|
||||
QmlIR::Alias *a = pool->New<QmlIR::Alias>();
|
||||
*static_cast<QV4::CompiledData::Alias*>(a) = *serializedAlias;
|
||||
object->aliases->append(a);
|
||||
}
|
||||
}
|
||||
|
||||
QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
|
||||
|
||||
const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable();
|
||||
|
@ -2205,6 +2215,11 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
|
|||
const QString name = unit->stringAt(compiledFunction->nameIndex);
|
||||
f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/0);
|
||||
|
||||
f->formals.allocate(pool, int(compiledFunction->nFormals));
|
||||
formalNameIdx = compiledFunction->formalsTable();
|
||||
for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
|
||||
f->formals[i] = *formalNameIdx;
|
||||
|
||||
object->functions->append(f);
|
||||
}
|
||||
|
||||
|
|
|
@ -2269,7 +2269,7 @@ bool Codegen::visit(DoWhileStatement *ast)
|
|||
|
||||
_block = loopbody;
|
||||
statement(ast->statement);
|
||||
_block->JUMP(loopcond);
|
||||
setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation());
|
||||
|
||||
_block = loopcond;
|
||||
condition(ast->expression, loopbody, loopend);
|
||||
|
@ -2334,7 +2334,7 @@ bool Codegen::visit(ForEachStatement *ast)
|
|||
return false;
|
||||
move(*init, _block->TEMP(temp));
|
||||
statement(ast->statement);
|
||||
_block->JUMP(foreachin);
|
||||
setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
|
||||
|
||||
_block = foreachin;
|
||||
|
||||
|
@ -2373,7 +2373,7 @@ bool Codegen::visit(ForStatement *ast)
|
|||
|
||||
_block = forbody;
|
||||
statement(ast->statement);
|
||||
_block->JUMP(forstep);
|
||||
setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
|
||||
|
||||
_block = forstep;
|
||||
statement(ast->expression);
|
||||
|
@ -2473,7 +2473,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
|
|||
int temp = _block->newTemp();
|
||||
move(identifier(ast->declaration->name.toString()), _block->TEMP(temp));
|
||||
statement(ast->statement);
|
||||
_block->JUMP(foreachin);
|
||||
setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
|
||||
|
||||
_block = foreachin;
|
||||
|
||||
|
@ -2512,7 +2512,7 @@ bool Codegen::visit(LocalForStatement *ast)
|
|||
|
||||
_block = forbody;
|
||||
statement(ast->statement);
|
||||
_block->JUMP(forstep);
|
||||
setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
|
||||
|
||||
_block = forstep;
|
||||
statement(ast->expression);
|
||||
|
@ -2813,7 +2813,7 @@ bool Codegen::visit(WhileStatement *ast)
|
|||
|
||||
_block = whilebody;
|
||||
statement(ast->statement);
|
||||
_block->JUMP(whilecond);
|
||||
setLocation(_block->JUMP(whilecond), ast->lastSourceLocation());
|
||||
|
||||
_block = whileend;
|
||||
leaveLoop();
|
||||
|
|
|
@ -76,7 +76,7 @@ bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const
|
|||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
if (header->sourceTimeStamp) {
|
||||
QFileInfo sourceCode(sourcePath);
|
||||
QDateTime sourceTimeStamp;
|
||||
if (sourceCode.exists())
|
||||
|
|
|
@ -77,13 +77,7 @@ namespace QV4 {
|
|||
|
||||
namespace CompiledData {
|
||||
|
||||
#ifdef V4_BOOTSTRAP
|
||||
static QString cacheFilePath(const QString &localSourcePath)
|
||||
{
|
||||
const QString localCachePath = localSourcePath + QLatin1Char('c');
|
||||
return localCachePath;
|
||||
}
|
||||
#else
|
||||
#if !defined(V4_BOOTSTRAP)
|
||||
static QString cacheFilePath(const QUrl &url)
|
||||
{
|
||||
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
|
||||
|
@ -101,8 +95,8 @@ static QString cacheFilePath(const QUrl &url)
|
|||
#ifndef V4_BOOTSTRAP
|
||||
CompilationUnit::CompilationUnit()
|
||||
: data(0)
|
||||
, engine(0)
|
||||
, runtimeStrings(0)
|
||||
, engine(0)
|
||||
, runtimeLookups(0)
|
||||
, runtimeRegularExpressions(0)
|
||||
, runtimeClasses(0)
|
||||
|
@ -374,7 +368,7 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory
|
|||
const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
|
||||
QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
|
||||
|
||||
if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
|
||||
if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
|
||||
*errorString = QStringLiteral("QML source file has moved to a different location.");
|
||||
return false;
|
||||
}
|
||||
|
@ -415,28 +409,29 @@ bool CompilationUnit::memoryMapCode(QString *errorString)
|
|||
#endif // V4_BOOTSTRAP
|
||||
|
||||
#if defined(V4_BOOTSTRAP)
|
||||
bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString)
|
||||
bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString)
|
||||
#else
|
||||
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
|
||||
#endif
|
||||
{
|
||||
errorString->clear();
|
||||
|
||||
#if !defined(V4_BOOTSTRAP)
|
||||
if (data->sourceTimeStamp == 0) {
|
||||
*errorString = QStringLiteral("Missing time stamp for source file");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !defined(V4_BOOTSTRAP)
|
||||
if (!QQmlFile::isLocalFile(unitUrl)) {
|
||||
*errorString = QStringLiteral("File has to be a local file.");
|
||||
return false;
|
||||
}
|
||||
const QString outputFileName = cacheFilePath(unitUrl);
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(temporaryfile)
|
||||
// Foo.qml -> Foo.qmlc
|
||||
QSaveFile cacheFile(cacheFilePath(unitUrl));
|
||||
QSaveFile cacheFile(outputFileName);
|
||||
if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
*errorString = cacheFile.errorString();
|
||||
return false;
|
||||
|
@ -492,10 +487,22 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
|
|||
return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
|
||||
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit;
|
||||
QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(irDocument->javaScriptCompilationUnit->data);
|
||||
QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(compilationUnit->data);
|
||||
auto ensureWritableUnit = [&jsUnit, &compilationUnit]() {
|
||||
if (jsUnit == compilationUnit->data) {
|
||||
char *unitCopy = (char*)malloc(jsUnit->unitSize);
|
||||
memcpy(unitCopy, jsUnit, jsUnit->unitSize);
|
||||
jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy);
|
||||
}
|
||||
};
|
||||
|
||||
QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable;
|
||||
|
||||
if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) {
|
||||
ensureWritableUnit();
|
||||
jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName);
|
||||
}
|
||||
|
||||
// Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
|
||||
// and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
|
||||
// the string table.
|
||||
|
@ -558,6 +565,7 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
|
|||
}
|
||||
|
||||
if (!signalParameterNameTable.isEmpty()) {
|
||||
ensureWritableUnit();
|
||||
Q_ASSERT(jsUnit != compilationUnit->data);
|
||||
const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32);
|
||||
uint newSize = jsUnit->unitSize + signalParameterTableSize;
|
||||
|
|
|
@ -817,13 +817,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
|
|||
// Called only when building QML, when we build the header for JS first and append QML data
|
||||
virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
|
||||
|
||||
#ifndef V4_BOOTSTRAP
|
||||
ExecutionEngine *engine;
|
||||
#endif
|
||||
|
||||
QV4::Heap::String **runtimeStrings; // Array
|
||||
|
||||
#ifndef V4_BOOTSTRAP
|
||||
ExecutionEngine *engine;
|
||||
|
||||
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
|
||||
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
|
||||
|
||||
|
@ -909,7 +907,7 @@ protected:
|
|||
|
||||
public:
|
||||
#if defined(V4_BOOTSTRAP)
|
||||
bool saveToDisk(const QString &unitUrl, QString *errorString);
|
||||
bool saveToDisk(const QString &outputFileName, QString *errorString);
|
||||
#else
|
||||
bool saveToDisk(const QUrl &unitUrl, QString *errorString);
|
||||
#endif
|
||||
|
|
|
@ -348,11 +348,7 @@ Module::~Module()
|
|||
|
||||
void Module::setFileName(const QString &name)
|
||||
{
|
||||
if (fileName.isEmpty())
|
||||
fileName = name;
|
||||
else {
|
||||
Q_ASSERT(fileName == name);
|
||||
}
|
||||
fileName = name;
|
||||
}
|
||||
|
||||
Function::Function(Module *module, Function *outer, const QString &name)
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "qqmldebugserviceinterfaces_p.h"
|
||||
|
||||
#include <private/qqmlengine_p.h>
|
||||
#include <private/qv4compileddata_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -181,12 +182,12 @@ bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName,
|
|||
return connector ? connector->open(configuration) : false;
|
||||
}
|
||||
|
||||
enum { HookCount = 3 };
|
||||
enum { HookCount = 4 };
|
||||
|
||||
// Only add to the end, and bump version if you do.
|
||||
quintptr Q_QML_EXPORT qtDeclarativeHookData[] = {
|
||||
// Version of this Array. Bump if you add to end.
|
||||
1,
|
||||
2,
|
||||
|
||||
// Number of entries in this array.
|
||||
HookCount,
|
||||
|
@ -194,7 +195,10 @@ quintptr Q_QML_EXPORT qtDeclarativeHookData[] = {
|
|||
// TypeInformationVersion, an integral value, bumped whenever private
|
||||
// object sizes or member offsets that are used in Qt Creator's
|
||||
// data structure "pretty printing" change.
|
||||
2
|
||||
3,
|
||||
|
||||
// Version of the cache data.
|
||||
QV4_DATA_STRUCTURE_VERSION
|
||||
};
|
||||
|
||||
Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0]));
|
||||
|
|
|
@ -210,7 +210,6 @@ QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringR
|
|||
|
||||
} // namespace
|
||||
|
||||
#if QT_CONFIG(library)
|
||||
struct RegisteredPlugin {
|
||||
QString uri;
|
||||
QPluginLoader* loader;
|
||||
|
@ -221,21 +220,23 @@ struct StringRegisteredPluginMap : public QMap<QString, RegisteredPlugin> {
|
|||
};
|
||||
|
||||
Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders
|
||||
|
||||
void qmlClearEnginePlugins()
|
||||
{
|
||||
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
|
||||
QMutexLocker lock(&plugins->mutex);
|
||||
#if QT_CONFIG(library)
|
||||
for (auto &plugin : qAsConst(*plugins)) {
|
||||
QPluginLoader* loader = plugin.loader;
|
||||
if (loader && !loader->unload())
|
||||
qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
|
||||
delete loader;
|
||||
}
|
||||
#endif
|
||||
plugins->clear();
|
||||
}
|
||||
|
||||
typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
@ -332,10 +333,9 @@ public:
|
|||
const QString &uri, const QString &url,
|
||||
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
|
||||
QList<QQmlError> *errors, bool lowPrecedence = false);
|
||||
#if QT_CONFIG(library)
|
||||
bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
|
||||
|
||||
bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
|
||||
const QString &qmldirPath, QList<QQmlError> *errors);
|
||||
#endif
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -959,7 +959,6 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
|
|||
return result;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(library)
|
||||
static QVector<QStaticPlugin> makePlugins()
|
||||
{
|
||||
QVector<QStaticPlugin> plugins;
|
||||
|
@ -1009,7 +1008,6 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
|
|||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(QT_SHARED) || !QT_CONFIG(library)
|
||||
static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
|
||||
|
@ -1030,7 +1028,6 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
|
|||
const QQmlTypeLoaderQmldirContent *qmldir,
|
||||
QList<QQmlError> *errors)
|
||||
{
|
||||
#if QT_CONFIG(library)
|
||||
Q_ASSERT(qmldir);
|
||||
|
||||
if (qmlImportTrace())
|
||||
|
@ -1143,22 +1140,6 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
|
|||
|
||||
database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath);
|
||||
}
|
||||
|
||||
#else
|
||||
Q_UNUSED(vmaj);
|
||||
Q_UNUSED(vmin);
|
||||
Q_UNUSED(database);
|
||||
Q_UNUSED(qmldir);
|
||||
|
||||
if (errors) {
|
||||
QQmlError error;
|
||||
error.setDescription(msgCannotLoadPlugin(uri, QQmlImportDatabase::tr("library loading is disabled")));
|
||||
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
|
||||
errors->prepend(error);
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif // library
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2014,7 +1995,6 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b
|
|||
bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath,
|
||||
const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
|
||||
{
|
||||
#if QT_CONFIG(library)
|
||||
// Dynamic plugins are differentiated by their filepath. For static plugins we
|
||||
// don't have that information so we use their address as key instead.
|
||||
const QString uniquePluginID = QString::asprintf("%p", instance);
|
||||
|
@ -2050,15 +2030,6 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba
|
|||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(instance);
|
||||
Q_UNUSED(basePath);
|
||||
Q_UNUSED(uri);
|
||||
Q_UNUSED(typeNamespace);
|
||||
Q_UNUSED(vmaj);
|
||||
Q_UNUSED(errors);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -2407,6 +2407,7 @@ void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit>
|
|||
m_document.reset(new QmlIR::Document(isDebugging()));
|
||||
QmlIR::IRLoader loader(unit->data, m_document.data());
|
||||
loader.load();
|
||||
m_document->jsModule.setFileName(finalUrlString());
|
||||
m_document->javaScriptCompilationUnit = unit;
|
||||
continueLoadFromIR();
|
||||
}
|
||||
|
@ -2507,6 +2508,8 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach
|
|||
{
|
||||
Q_ASSERT(m_compiledData.isNull());
|
||||
|
||||
const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit && m_document->javaScriptCompilationUnit->data->flags & QV4::CompiledData::Unit::PendingTypeCompilation;
|
||||
|
||||
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
|
||||
QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache);
|
||||
m_compiledData = compiler.compile();
|
||||
|
@ -2515,7 +2518,7 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach
|
|||
return;
|
||||
}
|
||||
|
||||
const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode;
|
||||
const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode && !typeRecompilation;
|
||||
if (trySaveToDisk) {
|
||||
QString errorString;
|
||||
if (m_compiledData->saveToDisk(url(), &errorString)) {
|
||||
|
|
|
@ -837,10 +837,9 @@ void QQDMIncubationTask::statusChanged(Status status)
|
|||
} else if (isDoneIncubating(status)) {
|
||||
Q_ASSERT(incubating);
|
||||
// The model was deleted from under our feet, cleanup ourselves
|
||||
if (incubating->object) {
|
||||
delete incubating->object;
|
||||
|
||||
incubating->object = 0;
|
||||
delete incubating->object;
|
||||
incubating->object = 0;
|
||||
if (incubating->contextData) {
|
||||
incubating->contextData->destroy();
|
||||
incubating->contextData = 0;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <private/qquickcontext2d_p.h>
|
||||
#include <private/qquickcontext2dtexture_p.h>
|
||||
#include <private/qsgadaptationlayer_p.h>
|
||||
#include <qsgtextureprovider.h>
|
||||
#include <QtQuick/private/qquickpixmapcache_p.h>
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
|
|
|
@ -42,7 +42,9 @@
|
|||
#include "qquickcanvasitem_p.h"
|
||||
#include <private/qquickcontext2dtexture_p.h>
|
||||
#include <private/qquickitem_p.h>
|
||||
#if QT_CONFIG(quick_shadereffect)
|
||||
#include <QtQuick/private/qquickshadereffectsource_p.h>
|
||||
#endif
|
||||
#include <qsgrendererinterface.h>
|
||||
|
||||
#include <QtQuick/private/qsgcontext_p.h>
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
//
|
||||
|
||||
#include "qquickitem_p.h"
|
||||
#include "qquickpainteditem.h"
|
||||
#include <QtGui/qcolor.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
|
@ -2397,7 +2397,6 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
|
|||
} else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
|
||||
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
|
||||
if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
|
||||
moveEvent->setAccepted(true);
|
||||
for (++grabItem; grabItem != grabber->end();) {
|
||||
QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
|
||||
if ((**grabItem)->contains(p)) {
|
||||
|
@ -2472,7 +2471,10 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
|
|||
event->keyboardModifiers(),
|
||||
event->type());
|
||||
QQuickDropEventEx::copyActions(&translatedEvent, *event);
|
||||
translatedEvent.setAccepted(event->isAccepted());
|
||||
QCoreApplication::sendEvent(item, &translatedEvent);
|
||||
event->setAccepted(translatedEvent.isAccepted());
|
||||
event->setDropAction(translatedEvent.dropAction());
|
||||
if (event->type() == QEvent::DragEnter) {
|
||||
if (translatedEvent.isAccepted()) {
|
||||
grabber->grab(item);
|
||||
|
@ -2593,9 +2595,14 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
|
|||
qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target;
|
||||
if (t != QEvent::MouseButtonRelease) {
|
||||
qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
|
||||
touchMouseId = tp.id();
|
||||
touchMouseDevice = event->device();
|
||||
touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabber(target);
|
||||
if (touchMouseId == -1) {
|
||||
// the point was grabbed as a pure touch point before, now it will be treated as mouse
|
||||
// but the old receiver still needs to be informed
|
||||
if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber())
|
||||
oldGrabber->touchUngrabEvent();
|
||||
}
|
||||
touchMouseId = tp.id();
|
||||
target->grabMouse();
|
||||
}
|
||||
filtered = true;
|
||||
|
|
|
@ -101,7 +101,7 @@ void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window)
|
|||
}
|
||||
}
|
||||
|
||||
void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
|
||||
void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
|
||||
{
|
||||
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
|
||||
if (!m_windows.contains(window))
|
||||
|
@ -174,7 +174,10 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
|
|||
|
||||
if (alsoSwap && window->isVisible()) {
|
||||
//Flush backingstore to window
|
||||
m_backingStores[window]->flush(softwareRenderer->flushRegion());
|
||||
if (!isNewExpose)
|
||||
m_backingStores[window]->flush(softwareRenderer->flushRegion());
|
||||
else
|
||||
m_backingStores[window]->flush(QRegion(QRect(QPoint(0,0), window->size())));
|
||||
cd->fireFrameSwapped();
|
||||
}
|
||||
|
||||
|
@ -206,7 +209,7 @@ void QSGSoftwareRenderLoop::exposureChanged(QQuickWindow *window)
|
|||
{
|
||||
if (window->isExposed()) {
|
||||
m_windows[window].updatePending = true;
|
||||
renderWindow(window);
|
||||
renderWindow(window, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
|
||||
void windowDestroyed(QQuickWindow *window) override;
|
||||
|
||||
void renderWindow(QQuickWindow *window);
|
||||
void renderWindow(QQuickWindow *window, bool isNewExpose = false);
|
||||
void exposureChanged(QQuickWindow *window) override;
|
||||
QImage grab(QQuickWindow *window) override;
|
||||
|
||||
|
|
|
@ -42,11 +42,33 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QSGDefaultGlyphNode::QSGDefaultGlyphNode()
|
||||
: m_glyphNodeType(RootGlyphNode)
|
||||
, m_dirtyGeometry(false)
|
||||
{
|
||||
setFlag(UsePreprocess);
|
||||
}
|
||||
|
||||
QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
|
||||
{
|
||||
if (m_glyphNodeType == SubGlyphNode)
|
||||
return;
|
||||
|
||||
qDeleteAll(m_nodesToDelete);
|
||||
m_nodesToDelete.clear();
|
||||
}
|
||||
|
||||
void QSGDefaultGlyphNode::setMaterialColor(const QColor &color)
|
||||
{
|
||||
static_cast<QSGTextMaskMaterial *>(m_material)->setColor(color);
|
||||
}
|
||||
|
||||
void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
|
||||
{
|
||||
QSGBasicGlyphNode::setGlyphs(position, glyphs);
|
||||
m_dirtyGeometry = true;
|
||||
}
|
||||
|
||||
void QSGDefaultGlyphNode::update()
|
||||
{
|
||||
QRawFont font = m_glyphs.rawFont();
|
||||
|
@ -84,4 +106,110 @@ void QSGDefaultGlyphNode::update()
|
|||
markDirty(DirtyGeometry);
|
||||
}
|
||||
|
||||
void QSGDefaultGlyphNode::preprocess()
|
||||
{
|
||||
qDeleteAll(m_nodesToDelete);
|
||||
m_nodesToDelete.clear();
|
||||
|
||||
if (m_dirtyGeometry)
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void QSGDefaultGlyphNode::updateGeometry()
|
||||
{
|
||||
// Remove previously created sub glyph nodes
|
||||
// We assume all the children are sub glyph nodes
|
||||
QSGNode *subnode = firstChild();
|
||||
while (subnode) {
|
||||
// We can't delete the node now as it might be in the preprocess list
|
||||
// It will be deleted in the next preprocess
|
||||
m_nodesToDelete.append(subnode);
|
||||
subnode = subnode->nextSibling();
|
||||
}
|
||||
removeAllChildNodes();
|
||||
|
||||
GlyphInfo glyphInfo;
|
||||
|
||||
const QVector<quint32> indexes = m_glyphs.glyphIndexes();
|
||||
const QVector<QPointF> positions = m_glyphs.positions();
|
||||
|
||||
const int maxGlyphs = (USHRT_MAX + 1) / 4; // 16384
|
||||
const int maxVertices = maxGlyphs * 4; // 65536
|
||||
const int maxIndexes = maxGlyphs * 6; // 98304
|
||||
|
||||
for (int i = 0; i < indexes.size(); ++i) {
|
||||
const int glyphIndex = indexes.at(i);
|
||||
const QPointF position = positions.at(i);
|
||||
|
||||
// As we use UNSIGNED_SHORT indexing in the geometry, we overload the
|
||||
// "glyphsInOtherNodes" concept as overflow for if there are more than
|
||||
// 65536 (16384 * 4) vertices to render which would otherwise exceed
|
||||
// the maximum index size. This will cause sub-nodes to be recursively
|
||||
// created to handle any number of glyphs.
|
||||
if (i >= maxGlyphs) {
|
||||
glyphInfo.indexes.append(glyphIndex);
|
||||
glyphInfo.positions.append(position);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!glyphInfo.indexes.isEmpty()) {
|
||||
QGlyphRun subNodeGlyphRun(m_glyphs);
|
||||
subNodeGlyphRun.setGlyphIndexes(glyphInfo.indexes);
|
||||
subNodeGlyphRun.setPositions(glyphInfo.positions);
|
||||
|
||||
QSGDefaultGlyphNode *subNode = new QSGDefaultGlyphNode();
|
||||
subNode->setGlyphNodeType(SubGlyphNode);
|
||||
subNode->setColor(m_color);
|
||||
subNode->setStyle(m_style);
|
||||
subNode->setStyleColor(m_styleColor);
|
||||
subNode->setGlyphs(m_position, subNodeGlyphRun);
|
||||
subNode->update();
|
||||
subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
|
||||
appendChildNode(subNode);
|
||||
|
||||
QSGGeometry *g = geometry();
|
||||
|
||||
QSGGeometry::TexturedPoint2D *vertexData = g->vertexDataAsTexturedPoint2D();
|
||||
quint16 *indexData = g->indexDataAsUShort();
|
||||
|
||||
QVector<QSGGeometry::TexturedPoint2D> tempVertexData(maxVertices);
|
||||
QVector<quint16> tempIndexData(maxIndexes);
|
||||
|
||||
for (int i = 0; i < maxGlyphs; i++) {
|
||||
tempVertexData[i * 4 + 0] = vertexData[i * 4 + 0];
|
||||
tempVertexData[i * 4 + 1] = vertexData[i * 4 + 1];
|
||||
tempVertexData[i * 4 + 2] = vertexData[i * 4 + 2];
|
||||
tempVertexData[i * 4 + 3] = vertexData[i * 4 + 3];
|
||||
|
||||
tempIndexData[i * 6 + 0] = indexData[i * 6 + 0];
|
||||
tempIndexData[i * 6 + 1] = indexData[i * 6 + 1];
|
||||
tempIndexData[i * 6 + 2] = indexData[i * 6 + 2];
|
||||
tempIndexData[i * 6 + 3] = indexData[i * 6 + 3];
|
||||
tempIndexData[i * 6 + 4] = indexData[i * 6 + 4];
|
||||
tempIndexData[i * 6 + 5] = indexData[i * 6 + 5];
|
||||
}
|
||||
|
||||
g->allocate(maxVertices, maxIndexes);
|
||||
vertexData = g->vertexDataAsTexturedPoint2D();
|
||||
indexData = g->indexDataAsUShort();
|
||||
|
||||
for (int i = 0; i < maxGlyphs; i++) {
|
||||
vertexData[i * 4 + 0] = tempVertexData[i * 4 + 0];
|
||||
vertexData[i * 4 + 1] = tempVertexData[i * 4 + 1];
|
||||
vertexData[i * 4 + 2] = tempVertexData[i * 4 + 2];
|
||||
vertexData[i * 4 + 3] = tempVertexData[i * 4 + 3];
|
||||
|
||||
indexData[i * 6 + 0] = tempIndexData[i * 6 + 0];
|
||||
indexData[i * 6 + 1] = tempIndexData[i * 6 + 1];
|
||||
indexData[i * 6 + 2] = tempIndexData[i * 6 + 2];
|
||||
indexData[i * 6 + 3] = tempIndexData[i * 6 + 3];
|
||||
indexData[i * 6 + 4] = tempIndexData[i * 6 + 4];
|
||||
indexData[i * 6 + 5] = tempIndexData[i * 6 + 5];
|
||||
}
|
||||
}
|
||||
|
||||
m_dirtyGeometry = false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -59,8 +59,31 @@ QT_BEGIN_NAMESPACE
|
|||
class QSGDefaultGlyphNode : public QSGBasicGlyphNode
|
||||
{
|
||||
public:
|
||||
QSGDefaultGlyphNode();
|
||||
~QSGDefaultGlyphNode();
|
||||
void setMaterialColor(const QColor &color) override;
|
||||
void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override;
|
||||
void update() override;
|
||||
void preprocess() override;
|
||||
void updateGeometry();
|
||||
|
||||
private:
|
||||
enum DefaultGlyphNodeType {
|
||||
RootGlyphNode,
|
||||
SubGlyphNode
|
||||
};
|
||||
|
||||
void setGlyphNodeType(DefaultGlyphNodeType type) { m_glyphNodeType = type; }
|
||||
|
||||
DefaultGlyphNodeType m_glyphNodeType;
|
||||
QLinkedList<QSGNode *> m_nodesToDelete;
|
||||
|
||||
struct GlyphInfo {
|
||||
QVector<quint32> indexes;
|
||||
QVector<QPointF> positions;
|
||||
};
|
||||
|
||||
uint m_dirtyGeometry: 1;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -345,12 +345,13 @@ void QQuickTransformAnimatorJob::postSync()
|
|||
}
|
||||
|
||||
QQuickItemPrivate *d = QQuickItemPrivate::get(m_target);
|
||||
#if QT_CONFIG(quick_shadereffect)
|
||||
if (d->extra.isAllocated()
|
||||
&& d->extra->layer
|
||||
&& d->extra->layer->enabled()) {
|
||||
d = QQuickItemPrivate::get(d->extra->layer->m_effectSource);
|
||||
}
|
||||
|
||||
#endif
|
||||
m_helper->node = d->itemNode();
|
||||
}
|
||||
|
||||
|
|
|
@ -1140,7 +1140,7 @@ QSize QQuickWidget::initialSize() const
|
|||
|
||||
/*!
|
||||
Returns the view's root \l {QQuickItem} {item}. Can be null
|
||||
when setContents/setSource has not been called, if they were called with
|
||||
when setSource() has not been called, if it was called with
|
||||
broken QtQuick code or while the QtQuick contents are being created.
|
||||
*/
|
||||
QQuickItem *QQuickWidget::rootObject() const
|
||||
|
|
|
@ -10,7 +10,7 @@ qtHaveModule(gui):qtConfig(animation) {
|
|||
quick \
|
||||
qmltest
|
||||
|
||||
qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
|
||||
qtConfig(quick-shadereffect):qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
|
||||
SUBDIRS += particles
|
||||
qtHaveModule(widgets): SUBDIRS += quickwidgets
|
||||
}
|
||||
|
|
|
@ -176,6 +176,7 @@ public:
|
|||
, m_captureContextInfo(false)
|
||||
, m_thrownValue(-1)
|
||||
, collector(engine)
|
||||
, m_resumeSpeed(QV4Debugger::FullThrottle)
|
||||
, m_debugger(0)
|
||||
{
|
||||
}
|
||||
|
@ -214,7 +215,7 @@ public slots:
|
|||
if (m_captureContextInfo)
|
||||
captureContextInfo(debugger);
|
||||
|
||||
debugger->resume(QV4Debugger::FullThrottle);
|
||||
debugger->resume(m_resumeSpeed);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -280,6 +281,7 @@ public:
|
|||
int context;
|
||||
};
|
||||
QVector<ExpressionRequest> m_expressionRequests;
|
||||
QV4Debugger::Speed m_resumeSpeed;
|
||||
QList<QJsonObject> m_expressionResults;
|
||||
QList<QJsonArray> m_expressionRefs;
|
||||
QV4Debugger *m_debugger;
|
||||
|
@ -324,7 +326,10 @@ private slots:
|
|||
void breakInWith();
|
||||
|
||||
void evaluateExpression();
|
||||
void stepToEndOfScript();
|
||||
|
||||
void lastLineOfLoop_data();
|
||||
void lastLineOfLoop();
|
||||
private:
|
||||
QV4Debugger *debugger() const
|
||||
{
|
||||
|
@ -758,6 +763,70 @@ void tst_qv4debugger::evaluateExpression()
|
|||
}
|
||||
}
|
||||
|
||||
void tst_qv4debugger::stepToEndOfScript()
|
||||
{
|
||||
QString script =
|
||||
"var ret = 0;\n"
|
||||
"ret += 4;\n"
|
||||
"ret += 1;\n"
|
||||
"ret += 5;\n";
|
||||
|
||||
debugger()->addBreakPoint("toEnd", 1);
|
||||
m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
|
||||
evaluateJavaScript(script, "toEnd");
|
||||
QVERIFY(m_debuggerAgent->m_wasPaused);
|
||||
QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Step);
|
||||
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 5);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(i);
|
||||
QCOMPARE(state.fileName, QString("toEnd"));
|
||||
QCOMPARE(state.lineNumber, i + 1);
|
||||
}
|
||||
|
||||
QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(4);
|
||||
QCOMPARE(state.fileName, QString("toEnd"));
|
||||
QCOMPARE(state.lineNumber, -4); // A return instruction without proper line number.
|
||||
}
|
||||
|
||||
void tst_qv4debugger::lastLineOfLoop_data()
|
||||
{
|
||||
QTest::addColumn<QString>("loopHead");
|
||||
QTest::addColumn<QString>("loopTail");
|
||||
|
||||
QTest::newRow("for") << "for (var i = 0; i < 10; ++i) {\n" << "}\n";
|
||||
QTest::newRow("for..in") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}\n";
|
||||
QTest::newRow("while") << "while (ret < 10) {\n" << "}\n";
|
||||
QTest::newRow("do..while") << "do {\n" << "} while (ret < 10);\n";
|
||||
}
|
||||
|
||||
void tst_qv4debugger::lastLineOfLoop()
|
||||
{
|
||||
QFETCH(QString, loopHead);
|
||||
QFETCH(QString, loopTail);
|
||||
|
||||
QString script =
|
||||
"var ret = 0;\n"
|
||||
+ loopHead +
|
||||
" if (ret == 2)\n"
|
||||
" ret += 4;\n" // breakpoint, then step over
|
||||
" else \n"
|
||||
" ret += 1;\n"
|
||||
+ loopTail;
|
||||
|
||||
debugger()->addBreakPoint("trueBranch", 4);
|
||||
m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
|
||||
evaluateJavaScript(script, "trueBranch");
|
||||
QVERIFY(m_debuggerAgent->m_wasPaused);
|
||||
QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Step);
|
||||
QVERIFY(m_debuggerAgent->m_statesWhenPaused.count() > 1);
|
||||
QV4Debugger::ExecutionState firstState = m_debuggerAgent->m_statesWhenPaused.first();
|
||||
QCOMPARE(firstState.fileName, QString("trueBranch"));
|
||||
QCOMPARE(firstState.lineNumber, 4);
|
||||
QV4Debugger::ExecutionState secondState = m_debuggerAgent->m_statesWhenPaused.at(1);
|
||||
QCOMPARE(secondState.fileName, QString("trueBranch"));
|
||||
QCOMPARE(secondState.lineNumber, 7);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qv4debugger)
|
||||
|
||||
#include "tst_qv4debugger.moc"
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[inFlickable]
|
||||
*
|
|
@ -800,7 +800,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable2()
|
|||
|
||||
QVERIFY(flickable->contentY() < 0);
|
||||
QVERIFY(flickable->isMoving());
|
||||
QCOMPARE(point11->pressed(), true);
|
||||
QCOMPARE(point11->pressed(), false);
|
||||
|
||||
QTest::touchEvent(window.data(), device).release(0, p1);
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <qtest.h>
|
||||
#include <QDebug>
|
||||
#include <QMimeData>
|
||||
#include <QTouchEvent>
|
||||
#include <QtQuick/QQuickItem>
|
||||
#include <QtQuick/QQuickView>
|
||||
|
@ -372,6 +373,8 @@ private slots:
|
|||
|
||||
void grabContentItemToImage();
|
||||
|
||||
void testDragEventPropertyPropagation();
|
||||
|
||||
private:
|
||||
QTouchDevice *touchDevice;
|
||||
QTouchDevice *touchDeviceWithVelocity;
|
||||
|
@ -2567,6 +2570,261 @@ void tst_qquickwindow::grabContentItemToImage()
|
|||
QTRY_COMPARE(created->property("success").toInt(), 1);
|
||||
}
|
||||
|
||||
class TestDropTarget : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TestDropTarget(QQuickItem *parent = 0)
|
||||
: QQuickItem(parent)
|
||||
, enterDropAction(Qt::CopyAction)
|
||||
, moveDropAction(Qt::CopyAction)
|
||||
, dropDropAction(Qt::CopyAction)
|
||||
, enterAccept(true)
|
||||
, moveAccept(true)
|
||||
, dropAccept(true)
|
||||
{
|
||||
setFlags(ItemAcceptsDrops);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
enterDropAction = Qt::CopyAction;
|
||||
moveDropAction = Qt::CopyAction;
|
||||
dropDropAction = Qt::CopyAction;
|
||||
enterAccept = true;
|
||||
moveAccept = true;
|
||||
dropAccept = true;
|
||||
}
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
event->setAccepted(enterAccept);
|
||||
event->setDropAction(enterDropAction);
|
||||
}
|
||||
|
||||
void dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
event->setAccepted(moveAccept);
|
||||
event->setDropAction(moveDropAction);
|
||||
}
|
||||
|
||||
void dropEvent(QDropEvent *event)
|
||||
{
|
||||
event->setAccepted(dropAccept);
|
||||
event->setDropAction(dropDropAction);
|
||||
}
|
||||
|
||||
Qt::DropAction enterDropAction;
|
||||
Qt::DropAction moveDropAction;
|
||||
Qt::DropAction dropDropAction;
|
||||
bool enterAccept;
|
||||
bool moveAccept;
|
||||
bool dropAccept;
|
||||
};
|
||||
|
||||
class DragEventTester {
|
||||
public:
|
||||
DragEventTester()
|
||||
: pos(60, 60)
|
||||
, actions(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)
|
||||
, buttons(Qt::LeftButton)
|
||||
, modifiers(Qt::NoModifier)
|
||||
{
|
||||
}
|
||||
|
||||
~DragEventTester() {
|
||||
qDeleteAll(events);
|
||||
events.clear();
|
||||
enterEvent = 0;
|
||||
moveEvent = 0;
|
||||
dropEvent = 0;
|
||||
leaveEvent = 0;
|
||||
}
|
||||
|
||||
void addEnterEvent()
|
||||
{
|
||||
enterEvent = new QDragEnterEvent(pos, actions, &data, buttons, modifiers);
|
||||
events.append(enterEvent);
|
||||
}
|
||||
|
||||
void addMoveEvent()
|
||||
{
|
||||
moveEvent = new QDragMoveEvent(pos, actions, &data, buttons, modifiers, QEvent::DragMove);
|
||||
events.append(moveEvent);
|
||||
}
|
||||
|
||||
void addDropEvent()
|
||||
{
|
||||
dropEvent = new QDropEvent(pos, actions, &data, buttons, modifiers, QEvent::Drop);
|
||||
events.append(dropEvent);
|
||||
}
|
||||
|
||||
void addLeaveEvent()
|
||||
{
|
||||
leaveEvent = new QDragLeaveEvent();
|
||||
events.append(leaveEvent);
|
||||
}
|
||||
|
||||
void sendDragEventSequence(QQuickWindow *window) const {
|
||||
for (int i = 0; i < events.size(); ++i) {
|
||||
QCoreApplication::sendEvent(window, events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Used for building events.
|
||||
QMimeData data;
|
||||
QPoint pos;
|
||||
Qt::DropActions actions;
|
||||
Qt::MouseButtons buttons;
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
|
||||
// Owns events.
|
||||
QList<QEvent *> events;
|
||||
|
||||
// Non-owner pointers for easy acccess.
|
||||
QDragEnterEvent *enterEvent;
|
||||
QDragMoveEvent *moveEvent;
|
||||
QDropEvent *dropEvent;
|
||||
QDragLeaveEvent *leaveEvent;
|
||||
};
|
||||
|
||||
void tst_qquickwindow::testDragEventPropertyPropagation()
|
||||
{
|
||||
QQuickWindow window;
|
||||
TestDropTarget dropTarget(window.contentItem());
|
||||
|
||||
// Setting the size is important because the QQuickWindow checks if the drag happened inside
|
||||
// the drop target.
|
||||
dropTarget.setSize(QSizeF(100, 100));
|
||||
|
||||
// Test enter events property propagation.
|
||||
// For enter events, only isAccepted gets propagated.
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.enterAccept = false;
|
||||
dropTarget.enterDropAction = Qt::IgnoreAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragEnterEvent* enterEvent = builder.enterEvent;
|
||||
QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.enterAccept = false;
|
||||
dropTarget.enterDropAction = Qt::CopyAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragEnterEvent* enterEvent = builder.enterEvent;
|
||||
QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.enterAccept = true;
|
||||
dropTarget.enterDropAction = Qt::IgnoreAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragEnterEvent* enterEvent = builder.enterEvent;
|
||||
QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.enterAccept = true;
|
||||
dropTarget.enterDropAction = Qt::CopyAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragEnterEvent* enterEvent = builder.enterEvent;
|
||||
QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
|
||||
}
|
||||
|
||||
// Test move events property propagation.
|
||||
// For move events, both isAccepted and dropAction get propagated.
|
||||
dropTarget.reset();
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.moveAccept = false;
|
||||
dropTarget.moveDropAction = Qt::IgnoreAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragMoveEvent* moveEvent = builder.moveEvent;
|
||||
QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
|
||||
QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.moveAccept = false;
|
||||
dropTarget.moveDropAction = Qt::CopyAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragMoveEvent* moveEvent = builder.moveEvent;
|
||||
QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
|
||||
QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.moveAccept = true;
|
||||
dropTarget.moveDropAction = Qt::IgnoreAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragMoveEvent* moveEvent = builder.moveEvent;
|
||||
QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
|
||||
QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.moveAccept = true;
|
||||
dropTarget.moveDropAction = Qt::CopyAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDragMoveEvent* moveEvent = builder.moveEvent;
|
||||
QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
|
||||
QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
|
||||
}
|
||||
|
||||
// Test drop events property propagation.
|
||||
// For drop events, both isAccepted and dropAction get propagated.
|
||||
dropTarget.reset();
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.dropAccept = false;
|
||||
dropTarget.dropDropAction = Qt::IgnoreAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDropEvent* dropEvent = builder.dropEvent;
|
||||
QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
|
||||
QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.dropAccept = false;
|
||||
dropTarget.dropDropAction = Qt::CopyAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDropEvent* dropEvent = builder.dropEvent;
|
||||
QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
|
||||
QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.dropAccept = true;
|
||||
dropTarget.dropDropAction = Qt::IgnoreAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDropEvent* dropEvent = builder.dropEvent;
|
||||
QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
|
||||
QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
|
||||
}
|
||||
{
|
||||
DragEventTester builder;
|
||||
dropTarget.dropAccept = true;
|
||||
dropTarget.dropDropAction = Qt::CopyAction;
|
||||
builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
|
||||
builder.sendDragEventSequence(&window);
|
||||
QDropEvent* dropEvent = builder.dropEvent;
|
||||
QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
|
||||
QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qquickwindow)
|
||||
|
||||
#include "tst_qquickwindow.moc"
|
||||
|
|
|
@ -71,7 +71,7 @@ Q_SIGNALS:
|
|||
|
||||
public:
|
||||
EventItem(QQuickItem *parent = 0)
|
||||
: QQuickItem(parent), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1)
|
||||
: QQuickItem(parent), touchUngrabCount(0), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1)
|
||||
{
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
}
|
||||
|
@ -111,11 +111,17 @@ public:
|
|||
eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0)));
|
||||
}
|
||||
|
||||
void touchUngrabEvent()
|
||||
{
|
||||
++touchUngrabCount;
|
||||
}
|
||||
|
||||
bool event(QEvent *event) {
|
||||
return QQuickItem::event(event);
|
||||
}
|
||||
|
||||
QList<Event> eventList;
|
||||
int touchUngrabCount;
|
||||
bool acceptMouse;
|
||||
bool acceptTouch;
|
||||
bool filterTouch; // when used as event filter
|
||||
|
@ -158,6 +164,7 @@ private slots:
|
|||
void mouseOverTouch();
|
||||
|
||||
void buttonOnFlickable();
|
||||
void touchButtonOnFlickable();
|
||||
void buttonOnDelayedPressFlickable_data();
|
||||
void buttonOnDelayedPressFlickable();
|
||||
void buttonOnTouch();
|
||||
|
@ -568,9 +575,10 @@ void tst_TouchMouse::buttonOnFlickable()
|
|||
QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1);
|
||||
QCOMPARE(window->mouseGrabberItem(), eventItem1);
|
||||
|
||||
p1 += QPoint(0, -10);
|
||||
QPoint p2 = p1 + QPoint(0, -10);
|
||||
QPoint p3 = p2 + QPoint(0, -10);
|
||||
int dragDelta = -qApp->styleHints()->startDragDistance();
|
||||
p1 += QPoint(0, dragDelta);
|
||||
QPoint p2 = p1 + QPoint(0, dragDelta);
|
||||
QPoint p3 = p2 + QPoint(0, dragDelta);
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
QTest::touchEvent(window.data(), device).move(0, p1, window.data());
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
|
@ -593,6 +601,66 @@ void tst_TouchMouse::buttonOnFlickable()
|
|||
QQuickTouchUtils::flush(window.data());
|
||||
}
|
||||
|
||||
void tst_TouchMouse::touchButtonOnFlickable()
|
||||
{
|
||||
// flickable - height 500 / 1000
|
||||
// - eventItem1 y: 100, height 100
|
||||
// - eventItem2 y: 300, height 100
|
||||
|
||||
QScopedPointer<QQuickView> window(createView());
|
||||
window->setSource(testFileUrl("buttononflickable.qml"));
|
||||
window->show();
|
||||
QQuickViewTestUtil::centerOnScreen(window.data());
|
||||
QVERIFY(QTest::qWaitForWindowActive(window.data()));
|
||||
QVERIFY(window->rootObject() != 0);
|
||||
|
||||
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
|
||||
QVERIFY(flickable);
|
||||
|
||||
EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
|
||||
QVERIFY(eventItem2);
|
||||
QCOMPARE(eventItem2->eventList.size(), 0);
|
||||
eventItem2->acceptTouch = true;
|
||||
|
||||
// press via touch, then drag: check that flickable moves and that the button gets ungrabbed
|
||||
QCOMPARE(eventItem2->eventList.size(), 0);
|
||||
QPoint p1 = QPoint(10, 310);
|
||||
QTest::touchEvent(window.data(), device).press(0, p1, window.data());
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
QCOMPARE(eventItem2->eventList.size(), 1);
|
||||
QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
|
||||
|
||||
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data());
|
||||
QVERIFY(windowPriv->touchMouseId == -1);
|
||||
auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent();
|
||||
QCOMPARE(pointerEvent->point(0)->grabber(), eventItem2);
|
||||
QCOMPARE(window->mouseGrabberItem(), nullptr);
|
||||
|
||||
int dragDelta = qApp->styleHints()->startDragDistance() * -0.7;
|
||||
p1 += QPoint(0, dragDelta);
|
||||
QPoint p2 = p1 + QPoint(0, dragDelta);
|
||||
QPoint p3 = p2 + QPoint(0, dragDelta);
|
||||
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
QTest::touchEvent(window.data(), device).move(0, p1, window.data());
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
QTest::touchEvent(window.data(), device).move(0, p2, window.data());
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
QTest::touchEvent(window.data(), device).move(0, p3, window.data());
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
|
||||
QVERIFY(eventItem2->eventList.size() > 2);
|
||||
QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate);
|
||||
QCOMPARE(eventItem2->touchUngrabCount, 1);
|
||||
QCOMPARE(window->mouseGrabberItem(), flickable);
|
||||
QVERIFY(windowPriv->touchMouseId != -1);
|
||||
QCOMPARE(pointerEvent->point(0)->grabber(), flickable);
|
||||
QVERIFY(flickable->isMovingVertically());
|
||||
|
||||
QTest::touchEvent(window.data(), device).release(0, p3, window.data());
|
||||
QQuickTouchUtils::flush(window.data());
|
||||
}
|
||||
|
||||
void tst_TouchMouse::buttonOnDelayedPressFlickable_data()
|
||||
{
|
||||
QTest::addColumn<bool>("scrollBeforeDelayIsOver");
|
||||
|
|
|
@ -109,7 +109,7 @@ void tst_toolsupport::offsets_data()
|
|||
= QTest::newRow("CompiledData::CompilationUnit::runtimeStrings")
|
||||
<< pmm_to_offsetof(&QV4::CompiledData::CompilationUnit::runtimeStrings);
|
||||
|
||||
data << 16 << 32;
|
||||
data << 12 << 24;
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -1,12 +1,52 @@
|
|||
qtPrepareTool(QML_CACHEGEN, qmlcachegen)
|
||||
static {
|
||||
message("QML cache generation ahead of time is not supported in static builds")
|
||||
return()
|
||||
}
|
||||
|
||||
qtPrepareTool(QML_CACHEGEN, qmlcachegen, _ARCH_CHECK)
|
||||
|
||||
isEmpty(TARGETPATH): error("Must set TARGETPATH (QML import name) for ahead-of-time QML cache generation")
|
||||
|
||||
!isEmpty(QT_TARGET_ARCH):QML_CACHEGEN_ARCH=$$QT_TARGET_ARCH
|
||||
else:QML_CACHEGEN_ARCH=$$QT_ARCH
|
||||
|
||||
qmlcachegen.input = QML_FILES
|
||||
qmlcachegen.output = ${QMAKE_FILE_IN}c
|
||||
qmlcachegen.commands = $$QML_CACHEGEN --target-architecture=$$QML_CACHEGEN_ARCH ${QMAKE_FILE_IN}
|
||||
qmlcachegen.name = Generate QML Cache ${QMAKE_FILE_IN}
|
||||
qmlcachegen.variable_out = AUX_QML_FILES
|
||||
QML_CACHEGEN_ARGS=--target-architecture=$$QML_CACHEGEN_ARCH
|
||||
|
||||
QMAKE_EXTRA_COMPILERS += qmlcachegen
|
||||
!system($$QML_CACHEGEN_ARCH_CHECK $$QML_CACHEGEN_ARGS --check-if-supported) {
|
||||
message("QML cache generation requested but target architecture $$QML_CACHEGEN_ARCH is not supported.")
|
||||
return()
|
||||
}
|
||||
|
||||
load(qt_build_paths)
|
||||
|
||||
prefix_build: QMLCACHE_DESTDIR = $$MODULE_BASE_OUTDIR/qml/$$TARGETPATH
|
||||
else: QMLCACHE_DESTDIR = $$[QT_INSTALL_QML]/$$TARGETPATH
|
||||
|
||||
CACHEGEN_FILES=
|
||||
qmlcacheinst.files =
|
||||
for(qmlf, QML_FILES) {
|
||||
contains(qmlf,.*\\.js$)|contains(qmlf,.*\\.qml$) {
|
||||
CACHEGEN_FILES += $$absolute_path($$qmlf, $$_PRO_FILE_PWD_)
|
||||
qmlcacheinst.files += $$QMLCACHE_DESTDIR/$$relative_path($$qmlf, $$_PRO_FILE_PWD_)c
|
||||
}
|
||||
}
|
||||
|
||||
defineReplace(qmlCacheOutputFileName) {
|
||||
return($$relative_path($$QMLCACHE_DESTDIR/$$relative_path($$1, $$_PRO_FILE_PWD_)c, $$OUT_PWD))
|
||||
}
|
||||
|
||||
qmlcacheinst.base = $$QMLCACHE_DESTDIR
|
||||
qmlcacheinst.path = $$[QT_INSTALL_QML]/$$TARGETPATH
|
||||
qmlcacheinst.CONFIG = no_check_exist
|
||||
|
||||
qmlcachegen.input = CACHEGEN_FILES
|
||||
qmlcachegen.output = ${QMAKE_FUNC_FILE_IN_qmlCacheOutputFileName}
|
||||
qmlcachegen.CONFIG = no_link target_predeps
|
||||
qmlcachegen.commands = $$QML_CACHEGEN $$QML_CACHEGEN_ARGS -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
|
||||
qmlcachegen.name = Generate QML Cache ${QMAKE_FILE_IN}
|
||||
qmlcachegen.variable_out = GENERATED_FILES
|
||||
|
||||
!debug_and_release|!build_all|CONFIG(release, debug|release) {
|
||||
QMAKE_EXTRA_COMPILERS += qmlcachegen
|
||||
INSTALLS += qmlcacheinst
|
||||
}
|
||||
|
|
|
@ -80,7 +80,40 @@ QString diagnosticErrorMessage(const QString &fileName, const QQmlJS::Diagnostic
|
|||
return message;
|
||||
}
|
||||
|
||||
static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
|
||||
// Ensure that ListElement objects keep all property assignments in their string form
|
||||
static void annotateListElements(QmlIR::Document *document)
|
||||
{
|
||||
QStringList listElementNames;
|
||||
|
||||
foreach (const QV4::CompiledData::Import *import, document->imports) {
|
||||
const QString uri = document->stringAt(import->uriIndex);
|
||||
if (uri != QStringLiteral("QtQml.Models") && uri != QStringLiteral("QtQuick"))
|
||||
continue;
|
||||
|
||||
QString listElementName = QStringLiteral("ListElement");
|
||||
const QString qualifier = document->stringAt(import->qualifierIndex);
|
||||
if (!qualifier.isEmpty()) {
|
||||
listElementName.prepend(QLatin1Char('.'));
|
||||
listElementName.prepend(qualifier);
|
||||
}
|
||||
listElementNames.append(listElementName);
|
||||
}
|
||||
|
||||
if (listElementNames.isEmpty())
|
||||
return;
|
||||
|
||||
foreach (QmlIR::Object *object, document->objects) {
|
||||
if (!listElementNames.contains(document->stringAt(object->inheritedTypeNameIndex)))
|
||||
continue;
|
||||
for (QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
|
||||
if (binding->type != QV4::CompiledData::Binding::Type_Script)
|
||||
continue;
|
||||
binding->stringIndex = document->registerString(object->bindingAsString(document, binding->value.compiledScriptIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
|
||||
{
|
||||
QmlIR::Document irDocument(/*debugMode*/false);
|
||||
|
||||
|
@ -96,7 +129,6 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
|
|||
error->message = QLatin1String("Error reading from ") + inputFileName + QLatin1Char(':') + f.errorString();
|
||||
return false;
|
||||
}
|
||||
irDocument.jsModule.sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -112,8 +144,10 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
|
|||
}
|
||||
}
|
||||
|
||||
annotateListElements(&irDocument);
|
||||
|
||||
{
|
||||
QmlIR::JSCodeGen v4CodeGen(inputFileName, irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
|
||||
QmlIR::JSCodeGen v4CodeGen(/*empty input file name*/QString(), irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
|
||||
for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
|
||||
if (object->functionsAndExpressions->count == 0)
|
||||
continue;
|
||||
|
@ -153,7 +187,7 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
|
|||
unit->flags |= QV4::CompiledData::Unit::PendingTypeCompilation;
|
||||
irDocument.javaScriptCompilationUnit->data = unit;
|
||||
|
||||
if (!irDocument.javaScriptCompilationUnit->saveToDisk(inputFileName, &error->message))
|
||||
if (!irDocument.javaScriptCompilationUnit->saveToDisk(outputFileName, &error->message))
|
||||
return false;
|
||||
|
||||
free(unit);
|
||||
|
@ -161,7 +195,7 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
|
||||
static bool compileJSFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
|
||||
{
|
||||
QmlIR::Document irDocument(/*debugMode*/false);
|
||||
|
||||
|
@ -177,7 +211,6 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
|
|||
error->message = QLatin1String("Error reading from ") + inputFileName + QLatin1Char(':') + f.errorString();
|
||||
return false;
|
||||
}
|
||||
irDocument.jsModule.sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
QQmlJS::Engine *engine = &irDocument.jsParserEngine;
|
||||
|
@ -217,7 +250,7 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
|
|||
|
||||
{
|
||||
QmlIR::JSCodeGen v4CodeGen(inputFileName, irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
|
||||
v4CodeGen.generateFromProgram(inputFileName, sourceCode, program, &irDocument.jsModule, QQmlJS::Codegen::GlobalCode);
|
||||
v4CodeGen.generateFromProgram(/*empty input file name*/QString(), sourceCode, program, &irDocument.jsModule, QQmlJS::Codegen::GlobalCode);
|
||||
QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
|
||||
if (!jsErrors.isEmpty()) {
|
||||
for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
|
||||
|
@ -233,7 +266,8 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
|
|||
|
||||
// ### translation binding simplification
|
||||
|
||||
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, /*executable allocator*/nullptr, &irDocument.jsModule, &irDocument.jsGenerator));
|
||||
QV4::ExecutableAllocator allocator;
|
||||
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
|
||||
// Disable lookups in non-standalone (aka QML) mode
|
||||
isel->setUseFastLookups(false);
|
||||
irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
|
||||
|
@ -243,7 +277,7 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
|
|||
unit->flags |= QV4::CompiledData::Unit::StaticData;
|
||||
irDocument.javaScriptCompilationUnit->data = unit;
|
||||
|
||||
if (!irDocument.javaScriptCompilationUnit->saveToDisk(inputFileName, &error->message)) {
|
||||
if (!irDocument.javaScriptCompilationUnit->saveToDisk(outputFileName, &error->message)) {
|
||||
engine->setDirectives(oldDirs);
|
||||
return false;
|
||||
}
|
||||
|
@ -270,11 +304,35 @@ int main(int argc, char **argv)
|
|||
QCommandLineOption targetArchitectureOption(QStringLiteral("target-architecture"), QCoreApplication::translate("main", "Target architecture"), QCoreApplication::translate("main", "architecture"));
|
||||
parser.addOption(targetArchitectureOption);
|
||||
|
||||
QCommandLineOption outputFileOption(QStringLiteral("o"), QCoreApplication::translate("main", "Output file name"), QCoreApplication::translate("main", "file name"));
|
||||
parser.addOption(outputFileOption);
|
||||
|
||||
QCommandLineOption checkIfSupportedOption(QStringLiteral("check-if-supported"), QCoreApplication::translate("main", "Check if cache generate is supported on the specified target architecture"));
|
||||
parser.addOption(checkIfSupportedOption);
|
||||
|
||||
parser.addPositionalArgument(QStringLiteral("[qml file]"),
|
||||
QStringLiteral("QML source file to generate cache for."));
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (!parser.isSet(targetArchitectureOption)) {
|
||||
fprintf(stderr, "Target architecture not specified. Please specify with --target-architecture=<arch>\n");
|
||||
parser.showHelp();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QScopedPointer<QV4::EvalISelFactory> isel;
|
||||
const QString targetArchitecture = parser.value(targetArchitectureOption);
|
||||
|
||||
isel.reset(QV4::JIT::createISelForArchitecture(targetArchitecture));
|
||||
|
||||
if (parser.isSet(checkIfSupportedOption)) {
|
||||
if (isel.isNull())
|
||||
return EXIT_FAILURE;
|
||||
else
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
const QStringList sources = parser.positionalArguments();
|
||||
if (sources.isEmpty()){
|
||||
parser.showHelp();
|
||||
|
@ -284,23 +342,22 @@ int main(int argc, char **argv)
|
|||
}
|
||||
const QString inputFile = sources.first();
|
||||
|
||||
QScopedPointer<QV4::EvalISelFactory> isel;
|
||||
const QString targetArchitecture = parser.value(targetArchitectureOption);
|
||||
|
||||
isel.reset(QV4::JIT::createISelForArchitecture(targetArchitecture));
|
||||
|
||||
if (!isel)
|
||||
isel.reset(new QV4::Moth::ISelFactory);
|
||||
|
||||
Error error;
|
||||
|
||||
QString outputFileName = inputFile + QLatin1Char('c');
|
||||
if (parser.isSet(outputFileOption))
|
||||
outputFileName = parser.value(outputFileOption);
|
||||
|
||||
if (inputFile.endsWith(QLatin1String(".qml"))) {
|
||||
if (!compileQmlFile(inputFile, isel.data(), &error)) {
|
||||
if (!compileQmlFile(inputFile, outputFileName, isel.data(), &error)) {
|
||||
error.augment(QLatin1String("Error compiling qml file: ")).print();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else if (inputFile.endsWith(QLatin1String(".js"))) {
|
||||
if (!compileJSFile(inputFile, isel.data(), &error)) {
|
||||
if (!compileJSFile(inputFile, outputFileName, isel.data(), &error)) {
|
||||
error.augment(QLatin1String("Error compiling qml file: ")).print();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
|
@ -6,19 +6,9 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
|
|||
SOURCES = qmlcachegen.cpp
|
||||
TARGET = qmlcachegen
|
||||
|
||||
BUILD_INTEGRATION = qmlcache.prf
|
||||
!force_independent {
|
||||
qmake_integration.input = BUILD_INTEGRATION
|
||||
qmake_integration.output = $$[QT_HOST_DATA]/mkspecs/features/${QMAKE_FILE_BASE}.prf
|
||||
qmake_integration.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
|
||||
qmake_integration.name = COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
|
||||
qmake_integration.CONFIG = no_clean no_link
|
||||
!contains(TEMPLATE, vc.*): qmake_integration.variable_out = GENERATED_FILES
|
||||
QMAKE_EXTRA_COMPILERS += qmake_integration
|
||||
}
|
||||
|
||||
qmake_integration_installs.files = $$BUILD_INTEGRATION
|
||||
qmake_integration_installs.path = $$[QT_HOST_DATA]/mkspecs/features
|
||||
INSTALLS += qmake_integration_installs
|
||||
build_integration.files = qmlcache.prf
|
||||
build_integration.path = $$[QT_HOST_DATA]/mkspecs/features
|
||||
prefix_build: INSTALLS += build_integration
|
||||
else: COPIES += build_integration
|
||||
|
||||
load(qt_tool)
|
||||
|
|
Loading…
Reference in New Issue