diff options
34 files changed, 724 insertions, 237 deletions
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index 07cbee1383..c68153aca8 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -49,6 +49,7 @@ #include <private/qquicksprite_p.h> #include <private/qquickspriteengine_p.h> #include <QOpenGLFunctions> +#include <QSGRendererInterface> #include <QtQuick/private/qsgshadersourcebuilder_p.h> #include <QtQuick/private/qsgtexture_p.h> #include <private/qqmlglobal_p.h> @@ -1469,8 +1470,17 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) update(); } +static inline bool isOpenGL(QSGRenderContext *rc) +{ + QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc); + return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL; +} + QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) { + if (!node && !isOpenGL(QQuickItemPrivate::get(this)->sceneGraphRenderContext())) + return 0; + if (m_pleaseReset){ if (node) delete node; diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp index 900dfe7ef7..2644c693ce 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp @@ -737,9 +737,13 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int const bool debugLayer = qEnvironmentVariableIntValue("QT_D3D_DEBUG") != 0; if (debugLayer) { qCDebug(QSG_LOG_INFO_GENERAL, "Enabling debug layer"); +#if !defined(Q_OS_WINRT) || !defined(NDEBUG) ComPtr<ID3D12Debug> debugController; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) debugController->EnableDebugLayer(); +#else + qCDebug(QSG_LOG_INFO_GENERAL, "Using DebugInterface will not allow certification to pass"); +#endif } QSGD3D12DeviceManager *dev = deviceManager(); diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 6d55b43354..a37d8ef7a5 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -4343,7 +4343,59 @@ private: * See LifeTimeIntervals::renumber for details on the numbering. */ class LifeRanges { - typedef QSet<Temp> LiveRegs; + class LiveRegs + { + typedef std::vector<int> Storage; + Storage regs; + + public: + void insert(int r) + { + if (find(r) == end()) + regs.push_back(r); + } + + void unite(const LiveRegs &other) + { + if (other.empty()) + return; + if (empty()) { + regs = other.regs; + return; + } + for (int r : other.regs) + insert(r); + } + + typedef Storage::iterator iterator; + iterator find(int r) + { return std::find(regs.begin(), regs.end(), r); } + + iterator begin() + { return regs.begin(); } + + iterator end() + { return regs.end(); } + + void erase(iterator it) + { regs.erase(it); } + + void remove(int r) + { + iterator it = find(r); + if (it != end()) + erase(it); + } + + bool empty() const + { return regs.empty(); } + + int size() const + { return int(regs.size()); } + + int at(int idx) const + { return regs.at(idx); } + }; std::vector<LiveRegs> _liveIn; std::vector<LifeTimeInterval *> _intervals; @@ -4351,14 +4403,21 @@ class LifeRanges { LifeTimeInterval &interval(const Temp *temp) { - LifeTimeInterval *<i = _intervals[temp->index]; - if (Q_UNLIKELY(!lti)) { - lti = new LifeTimeInterval; - lti->setTemp(*temp); - } + LifeTimeInterval *lti = _intervals[temp->index]; + Q_ASSERT(lti); return *lti; } + void ensureInterval(const IR::Temp &temp) + { + Q_ASSERT(!temp.isInvalid()); + LifeTimeInterval *<i = _intervals[temp.index]; + if (lti) + return; + lti = new LifeTimeInterval; + lti->setTemp(temp); + } + int defPosition(IR::Stmt *s) const { return usePosition(s) + 1; @@ -4412,13 +4471,13 @@ public: IRPrinter printer(&qout); for (size_t i = 0, ei = _liveIn.size(); i != ei; ++i) { qout << "L" << i <<" live-in: "; - QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i)); - if (live.isEmpty()) + auto live = _liveIn.at(i); + if (live.empty()) qout << "(none)"; std::sort(live.begin(), live.end()); for (int i = 0; i < live.size(); ++i) { if (i > 0) qout << ", "; - printer.print(&live[i]); + qout << '%' << live.at(i); } qout << endl; } @@ -4437,8 +4496,10 @@ private: for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { - if (Temp *t = phi->incoming.at(bbIndex)->asTemp()) - live.insert(*t); + if (Temp *t = phi->incoming.at(bbIndex)->asTemp()) { + ensureInterval(*t); + live.insert(t->index); + } } else { break; } @@ -4447,14 +4508,15 @@ private: const QVector<Stmt *> &statements = bb->statements(); - foreach (const Temp &opd, live) - interval(&opd).addRange(start(bb), end(bb)); + for (int reg : live) + _intervals[reg]->addRange(start(bb), end(bb)); InputOutputCollector collector; for (int i = statements.size() - 1; i >= 0; --i) { Stmt *s = statements.at(i); if (Phi *phi = s->asPhi()) { - LiveRegs::iterator it = live.find(*phi->targetTemp); + ensureInterval(*phi->targetTemp); + LiveRegs::iterator it = live.find(phi->targetTemp->index); if (it == live.end()) { // a phi node target that is only defined, but never used interval(phi->targetTemp).setFrom(start(bb)); @@ -4467,25 +4529,27 @@ private: collector.collect(s); //### TODO: use DefUses from the optimizer, because it already has all this information if (Temp *opd = collector.output) { + ensureInterval(*opd); LifeTimeInterval <i = interval(opd); lti.setFrom(defPosition(s)); - live.remove(lti.temp()); + live.remove(lti.temp().index); _sortedIntervals->add(<i); } //### TODO: use DefUses from the optimizer, because it already has all this information for (size_t i = 0, ei = collector.inputs.size(); i != ei; ++i) { Temp *opd = collector.inputs[i]; + ensureInterval(*opd); interval(opd).addRange(start(bb), usePosition(s)); - live.insert(*opd); + live.insert(opd->index); } } if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null. - foreach (const Temp &opd, live) - interval(&opd).addRange(start(bb), usePosition(loopEnd->terminator())); + for (int reg : live) + _intervals[reg]->addRange(start(bb), usePosition(loopEnd->terminator())); } - _liveIn[bb->index()] = live; + _liveIn[bb->index()] = std::move(live); } }; @@ -5055,7 +5119,7 @@ void LifeTimeInterval::setFrom(int from) { Q_ASSERT(from > 0); if (_ranges.isEmpty()) { // this is the case where there is no use, only a define - _ranges.push_front(Range(from, from)); + _ranges.prepend(Range(from, from)); if (_end == InvalidPosition) _end = from; } else { @@ -5069,7 +5133,7 @@ void LifeTimeInterval::addRange(int from, int to) { Q_ASSERT(to >= from); if (_ranges.isEmpty()) { - _ranges.push_front(Range(from, to)); + _ranges.prepend(Range(from, to)); _end = to; return; } @@ -5084,12 +5148,12 @@ void LifeTimeInterval::addRange(int from, int to) { break; p1->start = qMin(p->start, p1->start); p1->end = qMax(p->end, p1->end); - _ranges.pop_front(); + _ranges.remove(0); p = &_ranges.first(); } } else { if (to < p->start) { - _ranges.push_front(Range(from, to)); + _ranges.prepend(Range(from, to)); } else { Q_ASSERT(from > _ranges.last().end); _ranges.push_back(Range(from, to)); @@ -5130,7 +5194,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) } if (newInterval._ranges.first().end == atPosition) - newInterval._ranges.removeFirst(); + newInterval._ranges.remove(0); if (newStart == InvalidPosition) { // the temp stays inactive for the rest of its lifetime @@ -5150,7 +5214,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) break; } else { // the temp stays inactive for this interval, so remove it. - newInterval._ranges.removeFirst(); + newInterval._ranges.remove(0); } } Q_ASSERT(!newInterval._ranges.isEmpty()); @@ -5181,15 +5245,6 @@ void LifeTimeInterval::dump(QTextStream &out) const { out << " (register " << _reg << ")"; } -bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2) { - if (r1->_ranges.first().start == r2->_ranges.first().start) { - if (r1->isSplitFromInterval() == r2->isSplitFromInterval()) - return r1->_ranges.last().end < r2->_ranges.last().end; - else - return r1->isSplitFromInterval(); - } else - return r1->_ranges.first().start < r2->_ranges.first().start; -} bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2) { diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index ffba13f2ae..f64fb9c3d9 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -76,7 +76,7 @@ public: bool covers(int position) const { return start <= position && position <= end; } }; - typedef QVector<Range> Ranges; + typedef QVarLengthArray<Range, 4> Ranges; private: Temp _temp; @@ -90,7 +90,7 @@ public: enum { InvalidPosition = -1 }; enum { InvalidRegister = -1 }; - explicit LifeTimeInterval(int rangeCapacity = 2) + explicit LifeTimeInterval(int rangeCapacity = 4) : _end(InvalidPosition) , _reg(InvalidRegister) , _isFixedInterval(0) @@ -147,6 +147,17 @@ public: } }; +inline bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2) +{ + if (r1->_ranges.first().start == r2->_ranges.first().start) { + if (r1->isSplitFromInterval() == r2->isSplitFromInterval()) + return r1->_ranges.last().end < r2->_ranges.last().end; + else + return r1->isSplitFromInterval(); + } else + return r1->_ranges.first().start < r2->_ranges.first().start; +} + class LifeTimeIntervals { Q_DISABLE_COPY(LifeTimeIntervals) diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 9c839936c2..5e05f14192 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -152,11 +152,14 @@ Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::Ex , _executableAllocator(executableAllocator) , _isel(isel) { + _addrs.resize(_function->basicBlockCount()); + _patches.resize(_function->basicBlockCount()); + _labelPatches.resize(_function->basicBlockCount()); } void Assembler::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock) { - _addrs[block] = label(); + _addrs[block->index()] = label(); catchBlock = block->catchBlock; _nextBlock = nextBlock; } @@ -166,12 +169,12 @@ void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target) Q_UNUSED(current); if (target != _nextBlock) - _patches[target].append(jump()); + _patches[target->index()].push_back(jump()); } void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump) { - _patches[targetBlock].append(targetJump); + _patches[targetBlock->index()].push_back(targetJump); } void Assembler::addPatch(DataLabelPtr patch, Label target) @@ -179,12 +182,12 @@ void Assembler::addPatch(DataLabelPtr patch, Label target) DataLabelPatch p; p.dataLabel = patch; p.target = target; - _dataLabelPatches.append(p); + _dataLabelPatches.push_back(p); } void Assembler::addPatch(DataLabelPtr patch, IR::BasicBlock *target) { - _labelPatches[target].append(patch); + _labelPatches[target->index()].push_back(patch); } void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock, diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 2ef0db78c0..7d4d90882a 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -58,8 +58,6 @@ #include "private/qv4lookup_p.h" #include "qv4targetplatform_p.h" -#include <QtCore/QHash> -#include <QtCore/QStack> #include <config.h> #include <wtf/Vector.h> @@ -1073,8 +1071,8 @@ public: private: QScopedPointer<const StackLayout> _stackLayout; IR::Function *_function; - QHash<IR::BasicBlock *, Label> _addrs; - QHash<IR::BasicBlock *, QVector<Jump> > _patches; + std::vector<Label> _addrs; + std::vector<std::vector<Jump>> _patches; #ifndef QT_NO_DEBUG QVector<CallInfo> _callInfos; #endif @@ -1083,9 +1081,9 @@ private: DataLabelPtr dataLabel; Label target; }; - QList<DataLabelPatch> _dataLabelPatches; + std::vector<DataLabelPatch> _dataLabelPatches; - QHash<IR::BasicBlock *, QVector<DataLabelPtr> > _labelPatches; + std::vector<std::vector<DataLabelPtr>> _labelPatches; IR::BasicBlock *_nextBlock; QV4::ExecutableAllocator *_executableAllocator; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 2cb3596c33..dd3b803ca8 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -144,13 +144,10 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) Label endOfCode = label(); { - QHashIterator<IR::BasicBlock *, QVector<Jump> > it(_patches); - while (it.hasNext()) { - it.next(); - IR::BasicBlock *block = it.key(); - Label target = _addrs.value(block); + for (size_t i = 0, ei = _patches.size(); i != ei; ++i) { + Label target = _addrs.at(i); Q_ASSERT(target.isSet()); - foreach (Jump jump, it.value()) + for (Jump jump : qAsConst(_patches.at(i))) jump.linkTo(target, this); } } @@ -158,21 +155,18 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) JSC::JSGlobalData dummy(_executableAllocator); JSC::LinkBuffer linkBuffer(dummy, this, 0); - foreach (const DataLabelPatch &p, _dataLabelPatches) + for (const DataLabelPatch &p : qAsConst(_dataLabelPatches)) linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target)); // link exception handlers - foreach(Jump jump, exceptionPropagationJumps) + for (Jump jump : qAsConst(exceptionPropagationJumps)) linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel)); { - QHashIterator<IR::BasicBlock *, QVector<DataLabelPtr> > it(_labelPatches); - while (it.hasNext()) { - it.next(); - IR::BasicBlock *block = it.key(); - Label target = _addrs.value(block); + for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) { + Label target = _addrs.at(i); Q_ASSERT(target.isSet()); - foreach (DataLabelPtr label, it.value()) + for (DataLabelPtr label : _labelPatches.at(i)) linkBuffer.patch(label, linkBuffer.locationOf(target)); } } @@ -187,7 +181,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) if (showCode) { QHash<void*, const char*> functions; #ifndef QT_NO_DEBUG - foreach (CallInfo call, _callInfos) + for (CallInfo call : qAsConst(_callInfos)) functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName; #endif @@ -337,7 +331,7 @@ void InstructionSelection::run(int functionIndex) continue; _as->registerBlock(_block, nextBlock); - foreach (IR::Stmt *s, _block->statements()) { + for (IR::Stmt *s : _block->statements()) { if (s->location.isValid()) { if (int(s->location.startLine) != lastLine) { _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); @@ -1682,7 +1676,7 @@ void InstructionSelection::calculateRegistersToSave(const RegisterInformation &u regularRegistersToSave.clear(); fpRegistersToSave.clear(); - foreach (const RegisterInfo &ri, Assembler::getRegisterInfo()) { + for (const RegisterInfo &ri : Assembler::getRegisterInfo()) { #if defined(RESTORE_EBX_ON_CALL) if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) { regularRegistersToSave.append(ri); diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index deef719b67..350ab7e0c6 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -814,10 +814,10 @@ class ResolutionPhase Q_DISABLE_COPY(ResolutionPhase) LifeTimeIntervals::Ptr _intervals; - QVector<LifeTimeInterval *> _unprocessed; + QVector<LifeTimeInterval *> _unprocessedReverseOrder; IR::Function *_function; const std::vector<int> &_assignedSpillSlots; - QHash<IR::Temp, const LifeTimeInterval *> _intervalForTemp; + std::vector<const LifeTimeInterval *> _liveIntervals; const QVector<const RegisterInfo *> &_intRegs; const QVector<const RegisterInfo *> &_fpRegs; @@ -825,26 +825,26 @@ class ResolutionPhase std::vector<Move *> _loads; std::vector<Move *> _stores; - QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtStart; - QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtEnd; + std::vector<std::vector<const LifeTimeInterval *> > _liveAtStart; + std::vector<std::vector<const LifeTimeInterval *> > _liveAtEnd; public: - ResolutionPhase(const QVector<LifeTimeInterval *> &unprocessed, + ResolutionPhase(QVector<LifeTimeInterval *> &&unprocessedReversedOrder, const LifeTimeIntervals::Ptr &intervals, IR::Function *function, const std::vector<int> &assignedSpillSlots, const QVector<const RegisterInfo *> &intRegs, const QVector<const RegisterInfo *> &fpRegs) : _intervals(intervals) + , _unprocessedReverseOrder(unprocessedReversedOrder) , _function(function) , _assignedSpillSlots(assignedSpillSlots) , _intRegs(intRegs) , _fpRegs(fpRegs) , _currentStmt(0) { - _unprocessed = unprocessed; - _liveAtStart.reserve(function->basicBlockCount()); - _liveAtEnd.reserve(function->basicBlockCount()); + _liveAtStart.resize(function->basicBlockCount()); + _liveAtEnd.resize(function->basicBlockCount()); } void run() { @@ -883,7 +883,7 @@ private: cleanOldIntervals(_intervals->startPosition(bb)); addNewIntervals(_intervals->startPosition(bb)); - _liveAtStart[bb] = _intervalForTemp.values(); + _liveAtStart[bb->index()] = _liveIntervals; for (int i = 0, ei = statements.size(); i != ei; ++i) { _currentStmt = statements.at(i); @@ -905,24 +905,24 @@ private: } cleanOldIntervals(_intervals->endPosition(bb)); - _liveAtEnd[bb] = _intervalForTemp.values(); + _liveAtEnd[bb->index()] = _liveIntervals; if (DebugRegAlloc) { QBuffer buf; buf.open(QIODevice::WriteOnly); QTextStream os(&buf); os << "Intervals live at the start of L" << bb->index() << ":" << endl; - if (_liveAtStart[bb].isEmpty()) + if (_liveAtStart[bb->index()].empty()) os << "\t(none)" << endl; - for (const LifeTimeInterval *i : _liveAtStart.value(bb)) { + for (const LifeTimeInterval *i : _liveAtStart.at(bb->index())) { os << "\t"; i->dump(os); os << endl; } os << "Intervals live at the end of L" << bb->index() << ":" << endl; - if (_liveAtEnd[bb].isEmpty()) + if (_liveAtEnd[bb->index()].empty()) os << "\t(none)" << endl; - for (const LifeTimeInterval *i : _liveAtEnd.value(bb)) { + for (const LifeTimeInterval *i : _liveAtEnd.at(bb->index())) { os << "\t"; i->dump(os); os << endl; @@ -935,9 +935,19 @@ private: } + const LifeTimeInterval *findLiveInterval(Temp *t) const + { + for (const LifeTimeInterval *lti : _liveIntervals) { + if (lti->temp() == *t) + return lti; + } + + return nullptr; + } + void maybeGenerateSpill(Temp *t) { - const LifeTimeInterval *i = _intervalForTemp[*t]; + const LifeTimeInterval *i = findLiveInterval(t); if (i->reg() == LifeTimeInterval::InvalidRegister) return; @@ -953,26 +963,27 @@ private: if (position == Stmt::InvalidId) return; - while (!_unprocessed.isEmpty()) { - const LifeTimeInterval *i = _unprocessed.constFirst(); + while (!_unprocessedReverseOrder.isEmpty()) { + const LifeTimeInterval *i = _unprocessedReverseOrder.constLast(); if (i->start() > position) break; Q_ASSERT(!i->isFixedInterval()); - _intervalForTemp[i->temp()] = i; + _liveIntervals.push_back(i); // qDebug() << "-- Activating interval for temp" << i->temp().index; - _unprocessed.removeFirst(); + _unprocessedReverseOrder.removeLast(); } } void cleanOldIntervals(int position) { - QMutableHashIterator<Temp, const LifeTimeInterval *> it(_intervalForTemp); - while (it.hasNext()) { - const LifeTimeInterval *i = it.next().value(); - if (i->end() < position || i->isFixedInterval()) - it.remove(); + for (size_t it = 0; it != _liveIntervals.size(); ) { + const LifeTimeInterval *lti = _liveIntervals.at(it); + if (lti->end() < position || lti->isFixedInterval()) + _liveIntervals.erase(_liveIntervals.begin() + it); + else + ++it; } } @@ -1019,7 +1030,7 @@ private: int successorStart = _intervals->startPosition(successor); Q_ASSERT(successorStart > 0); - for (const LifeTimeInterval *it : _liveAtStart.value(successor)) { + for (const LifeTimeInterval *it : _liveAtStart.at(successor->index())) { bool isPhiTarget = false; Expr *moveFrom = 0; @@ -1033,7 +1044,7 @@ private: Temp *t = opd->asTemp(); Q_ASSERT(t); - for (const LifeTimeInterval *it2 : _liveAtEnd.value(predecessor)) { + for (const LifeTimeInterval *it2 : _liveAtEnd.at(predecessor->index())) { if (it2->temp() == *t && it2->reg() != LifeTimeInterval::InvalidRegister && it2->covers(predecessorEnd)) { @@ -1048,7 +1059,7 @@ private: } } } else { - for (const LifeTimeInterval *predIt : _liveAtEnd.value(predecessor)) { + for (const LifeTimeInterval *predIt : _liveAtEnd.at(predecessor->index())) { if (predIt->temp() == it->temp()) { if (predIt->reg() != LifeTimeInterval::InvalidRegister && predIt->covers(predecessorEnd)) { @@ -1198,7 +1209,7 @@ private: if (t->kind != Temp::VirtualRegister) return; - const LifeTimeInterval *i = _intervalForTemp[*t]; + const LifeTimeInterval *i = findLiveInterval(t); Q_ASSERT(i->isValid()); if (_currentStmt != 0 && i->start() == usePosition(_currentStmt)) { @@ -1314,8 +1325,13 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt) if (DebugRegAlloc) dump(function); - std::sort(_handled.begin(), _handled.end(), LifeTimeInterval::lessThan); - ResolutionPhase(_handled, _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run(); + // sort the ranges in reverse order, so the ResolutionPhase can take from the end (and thereby + // prevent the copy overhead that taking from the beginning would give). + std::sort(_handled.begin(), _handled.end(), + [](const LifeTimeInterval *r1, const LifeTimeInterval *r2) -> bool { + return LifeTimeInterval::lessThan(r2, r1); + }); + ResolutionPhase(std::move(_handled), _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run(); function->tempCount = *std::max_element(_assignedSpillSlots.begin(), _assignedSpillSlots.end()) + 1; diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 6f0a7374c3..7e265258d5 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -563,7 +563,7 @@ public: #endif // Linux on MIPS (32 bit) public: // utility functions - static RegisterInformation getRegisterInfo() + static const RegisterInformation getRegisterInfo() { static const RegisterInformation info = getPlatformRegisterInfo(); diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index d27eef1d79..f8e0d8763b 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -285,12 +285,30 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) if (!ctx->argc() || ctx->args()[0].isUndefined()) return RuntimeHelpers::toString(scope.engine, v); - double precision = ctx->args()[0].toInt32(); + int precision = ctx->args()[0].toInt32(); if (precision < 1 || precision > 21) { ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"))); return ctx->engine()->throwRangeError(error); } - QString result = NumberLocale::instance()->toString(v->asDouble(), 'g', precision); + // TODO: Once we get a NumberOption to retain trailing zeroes, replace the code below with: + // QString result = NumberLocale::instance()->toString(v->asDouble(), 'g', precision); + QByteArray format = "%#." + QByteArray::number(precision) + "g"; + QString result = QString::asprintf(format.constData(), v->asDouble()); + if (result.endsWith(QLatin1Char('.'))) { + // This is 'f' notation, not 'e'. + result.chop(1); + } else { + int ePos = result.indexOf(QLatin1Char('e')); + if (ePos != -1) { + Q_ASSERT(ePos + 2 < result.length()); // always '+' or '-', and number, after 'e' + Q_ASSERT(ePos > 0); // 'e' is not the first character + + if (result.at(ePos + 2) == QLatin1Char('0')) // Drop leading zeroes in exponent + result = result.remove(ePos + 2, 1); + if (result.at(ePos - 1) == QLatin1Char('.')) // Drop trailing dots before 'e' + result = result.remove(ePos - 1, 1); + } + } return scope.engine->newString(result)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 633c5f60c9..9462101a2a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -44,7 +44,6 @@ #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlbinding_p.h> #include <private/qjsvalue_p.h> -#include <private/qqmlaccessors_p.h> #include <private/qqmlexpression_p.h> #include <private/qqmlglobal_p.h> #include <private/qqmltypewrapper_p.h> @@ -115,93 +114,57 @@ static QPair<QObject *, int> extractQtSignal(const Value &value) return qMakePair((QObject *)0, -1); } - -struct ReadAccessor { - static inline void Indirect(QObject *object, const QQmlPropertyData &property, - void *output, QQmlNotifier **n) - { - Q_ASSERT(n == 0); - Q_UNUSED(n); - - void *args[] = { output, 0 }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex(), args); - } - - static inline void Direct(QObject *object, const QQmlPropertyData &property, - void *output, QQmlNotifier **n) - { - Q_ASSERT(n == 0); - Q_UNUSED(n); - - void *args[] = { output, 0 }; - object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex(), args); - } - - static inline void Accessor(QObject *object, const QQmlPropertyData &property, - void *output, QQmlNotifier **n) - { - Q_ASSERT(property.accessors()); - - property.accessors()->read(object, output); - if (n) property.accessors()->notifier(object, n); - } -}; - -// Load value properties -template<void (*ReadFunction)(QObject *, const QQmlPropertyData &, - void *, QQmlNotifier **)> -static QV4::ReturnedValue LoadProperty(QV4::ExecutionEngine *v4, QObject *object, - const QQmlPropertyData &property, - QQmlNotifier **notifier) +static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object, + const QQmlPropertyData &property) { Q_ASSERT(!property.isFunction()); QV4::Scope scope(v4); if (property.isQObject()) { QObject *rv = 0; - ReadFunction(object, property, &rv, notifier); + property.readProperty(object, &rv); return QV4::QObjectWrapper::wrap(v4, rv); } else if (property.isQList()) { return QmlListWrapper::create(v4, object, property.coreIndex(), property.propType()); } else if (property.propType() == QMetaType::QReal) { qreal v = 0; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QV4::Encode(v); } else if (property.propType() == QMetaType::Int || property.isEnum()) { int v = 0; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QV4::Encode(v); } else if (property.propType() == QMetaType::Bool) { bool v = false; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QV4::Encode(v); } else if (property.propType() == QMetaType::QString) { QString v; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return v4->newString(v)->asReturnedValue(); } else if (property.propType() == QMetaType::UInt) { uint v = 0; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QV4::Encode(v); } else if (property.propType() == QMetaType::Float) { float v = 0; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QV4::Encode(v); } else if (property.propType() == QMetaType::Double) { double v = 0; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QV4::Encode(v); } else if (property.isV4Handle()) { QQmlV4Handle handle; - ReadFunction(object, property, &handle, notifier); + property.readProperty(object, &handle); return handle; } else if (property.propType() == qMetaTypeId<QJSValue>()) { QJSValue v; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); return QJSValuePrivate::convertedToValue(v4, v); } else if (property.isQVariant()) { QVariant v; - ReadFunction(object, property, &v, notifier); + property.readProperty(object, &v); if (QQmlValueTypeFactory::isValueType(v.userType())) { if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(v.userType())) @@ -210,13 +173,9 @@ static QV4::ReturnedValue LoadProperty(QV4::ExecutionEngine *v4, QObject *object return scope.engine->fromVariant(v); } else if (QQmlValueTypeFactory::isValueType(property.propType())) { - Q_ASSERT(notifier == 0); - if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property.propType())) return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, property.propType()); } else { - Q_ASSERT(notifier == 0); - // see if it's a sequence type bool succeeded = false; QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType(), object, property.coreIndex(), &succeeded)); @@ -231,7 +190,7 @@ static QV4::ReturnedValue LoadProperty(QV4::ExecutionEngine *v4, QObject *object return QV4::Encode::undefined(); } else { QVariant v(property.propType(), (void *)0); - ReadFunction(object, property, v.data(), notifier); + property.readProperty(object, v.data()); return scope.engine->fromVariant(v); } } @@ -352,29 +311,6 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; - if (property->hasAccessors()) { - QQmlNotifier *n = 0; - QQmlNotifier **nptr = 0; - - if (ep && ep->propertyCapture && property->accessors()->notifier) - nptr = &n; - - Scope scope(engine); - QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr)); - - if (captureRequired && !property->isConstant()) { - if (property->accessors()->notifier) { - if (n && ep->propertyCapture) - ep->propertyCapture->captureProperty(n); - } else { - if (ep->propertyCapture) - ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex()); - } - } - - return rv->asReturnedValue(); - } - if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex()); @@ -382,10 +318,8 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeProperty(property->coreIndex()); - } else if (property->isDirect()) { - return LoadProperty<ReadAccessor::Direct>(engine, object, *property, 0); } else { - return LoadProperty<ReadAccessor::Indirect>(engine, object, *property, 0); + return loadProperty(engine, object, *property); } } diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 87be140cbb..4244b16210 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -49,7 +49,8 @@ SOURCES += \ $$PWD/qqmlfileselector.cpp \ $$PWD/qqmlobjectcreator.cpp \ $$PWD/qqmldirparser.cpp \ - $$PWD/qqmldelayedcallqueue.cpp + $$PWD/qqmldelayedcallqueue.cpp \ + $$PWD/qqmlloggingcategory.cpp HEADERS += \ $$PWD/qqmlglobal_p.h \ @@ -121,7 +122,8 @@ HEADERS += \ $$PWD/qqmlfileselector.h \ $$PWD/qqmlobjectcreator_p.h \ $$PWD/qqmldirparser_p.h \ - $$PWD/qqmldelayedcallqueue_p.h + $$PWD/qqmldelayedcallqueue_p.h \ + $$PWD/qqmlloggingcategory_p.h include(ftw/ftw.pri) include(v8/v8.pri) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 0cc96be5a8..7e4fe73ba1 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -89,6 +89,7 @@ #include <private/qqmlobjectmodel_p.h> #include <private/qquickworkerscript_p.h> #include <private/qqmlinstantiator_p.h> +#include <private/qqmlloggingcategory_p.h> #ifdef Q_OS_WIN // for %APPDATA% # include <qt_windows.h> @@ -187,6 +188,7 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1 qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser); qmlRegisterType<QQmlInstanceModel>(); + qmlRegisterType<QQmlLoggingCategory>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "LoggingCategory"); //Only available in >=2.8 } diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 4b54123892..ebc4d49c36 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -235,7 +235,7 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration) g->connect(n); } - if (duration == OnlyOnce) + if (duration == Permanently) expression->permanentGuards.prepend(g); else expression->activeGuards.prepend(g); diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp new file mode 100644 index 0000000000..88cf14cba0 --- /dev/null +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlloggingcategory_p.h" + +#include <QtQml/qqmlinfo.h> + +/*! + \qmltype LoggingCategory + \ingroup qml-utility-elements + \inqmlmodule QtQml + \brief Defines a logging category in QML + \since 5.8 + + A logging category can be passed to console.log() and friends as the first argument. + If supplied to to the logger the LoggingCategory's name will be used as Logging Category + otherwise the default logging category will be used. + + \qml + import QtQuick 2.8 + + Item { + LoggingCategory { + id: category + name: "com.qt.category" + } + + Component.onCompleted: { + console.log(category, "message"); + } + } + \endqml + + \note As the creation of objects is expensive, it is encouraged to put the needed + LoggingCategory definitions into a singleton and import this where needed. + + \sa QLoggingCategory +*/ + +/*! + \qmlproperty string QtQml::LoggingCategory::name + + Holds the name of the logging category. + + \note This property needs to be set when declaring the LoggingCategory + and cannot be changed later. + + \sa QLoggingCategory::name() +*/ + +QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent) + : QObject(parent) + , m_initialized(false) +{ +} + +QQmlLoggingCategory::~QQmlLoggingCategory() +{ +} + +QString QQmlLoggingCategory::name() const +{ + return QString::fromUtf8(m_name); +} + +QLoggingCategory *QQmlLoggingCategory::category() const +{ + return m_category.data(); +} + +void QQmlLoggingCategory::classBegin() +{ +} + +void QQmlLoggingCategory::componentComplete() +{ + m_initialized = true; + if (m_name.isNull()) + qmlInfo(this) << QString(QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !")); +} + +void QQmlLoggingCategory::setName(const QString &name) +{ + if (m_initialized) { + qmlInfo(this) << QString(QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created")); + return; + } + + m_name = name.toUtf8(); + QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData())); + m_category.swap(category); +} diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h new file mode 100644 index 0000000000..2b7f2f5b53 --- /dev/null +++ b/src/qml/qml/qqmlloggingcategory_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLLOGGINGCATEGORY_P_H +#define QQMLLOGGINGCATEGORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qloggingcategory.h> + +#include <QtQml/qqmlparserstatus.h> + +QT_BEGIN_NAMESPACE + +class QQmlLoggingCategory : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + Q_PROPERTY(QString name READ name WRITE setName) + +public: + QQmlLoggingCategory(QObject *parent = 0); + virtual ~QQmlLoggingCategory(); + + QString name() const; + void setName(const QString &name); + + QLoggingCategory *category() const; + + void classBegin() override; + void componentComplete() override; + +private: + QByteArray m_name; + QScopedPointer<QLoggingCategory> m_category; + bool m_initialized; +}; + +QT_END_NAMESPACE + +#endif // QQMLLOGGINGCATEGORY_H diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 5c53e342f3..ed00eddb30 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -150,7 +150,7 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p) Q_ASSERT(p.revision() <= Q_INT16_MAX); setRevision(p.revision()); - _flags = fastFlagsForProperty(p); + setFlags(fastFlagsForProperty(p)); int type = static_cast<int>(p.type()); if (type == QMetaType::QObjectStar) { @@ -171,7 +171,7 @@ void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine) setPropType(p.userType()); setCoreIndex(p.propertyIndex()); setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); - _flags = fastFlagsForProperty(p); + setFlags(fastFlagsForProperty(p)); flagsForPropertyType(propType(), engine, _flags); Q_ASSERT(p.revision() <= Q_INT16_MAX); setRevision(p.revision()); @@ -344,7 +344,7 @@ void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Fl data.setPropType(propType); data.setCoreIndex(coreIndex); data.setNotifyIndex(notifyIndex); - data._flags = flags; + data.setFlags(flags); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -363,7 +363,7 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag QQmlPropertyData data; data.setPropType(QVariant::Invalid); data.setCoreIndex(coreIndex); - data._flags = flags; + data.setFlags(flags); data.setArguments(nullptr); QQmlPropertyData handler = data; @@ -409,7 +409,7 @@ void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flag args->argumentsValid = true; data.setArguments(args); - data._flags = flags; + data.setFlags(flags); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -568,9 +568,9 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *sigdata = 0; if (m.methodType() == QMetaMethod::Signal) - data->_flags = signalFlags; + data->setFlags(signalFlags); else - data->_flags = methodFlags; + data->setFlags(methodFlags); data->lazyLoad(m); data->_flags.isDirect = !dynamicMetaObject; @@ -650,7 +650,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart]; - data->_flags = propertyFlags; + data->setFlags(propertyFlags); data->lazyLoad(p); data->_flags.isDirect = !dynamicMetaObject; @@ -672,16 +672,18 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, setNamedProperty(propName, ii, data, (old != 0)); } - QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str); - - // Fast properties may not be overrides or revisioned - Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision() == 0)); + bool isGadget = true; + for (const QMetaObject *it = metaObject; it != nullptr; it = it->superClass()) { + if (it == &QObject::staticMetaObject) + isGadget = false; + } - if (accessorProperty) { - data->setAccessors(accessorProperty->accessors); - } else if (old) { + if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept + data->_flags.isDirect = false; + else + data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset); + if (old) data->markAsOverrideOf(old); - } } } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 63a9c63d90..f28b2d0599 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -86,6 +86,8 @@ template <typename T> class QQmlPropertyCacheAliasCreator; class QQmlPropertyRawData { public: + typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction; + struct Flags { enum Types { OtherType = 0, @@ -100,6 +102,14 @@ public: QVariantType = 9 // Property is a QVariant }; + // The _otherBits (which "pad" the Flags struct to align it nicely) are used + // to store the relative property index. It will only get used when said index fits. See + // trySetStaticMetaCallFunction for details. + // (Note: this padding is done here, because certain compilers have surprising behavior + // when an enum is declared in-between two bit fields.) + enum { BitsLeftInFlags = 10 }; + unsigned _otherBits : BitsLeftInFlags; // align to 32 bits + // Can apply to all properties, except IsFunction unsigned isConstant : 1; // Has CONST flag unsigned isWritable : 1; // Has WRITE function @@ -126,15 +136,18 @@ public: unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved unsigned overrideIndexIsProperty: 1; - unsigned _padding : 10; // align to 32 bits - inline Flags(); inline bool operator==(const Flags &other) const; inline void copyPropertyTypeFlags(Flags from); }; Flags flags() const { return _flags; } - void setFlags(Flags f) { _flags = f; } + void setFlags(Flags f) + { + unsigned otherBits = _flags._otherBits; + _flags = f; + _flags._otherBits = otherBits; + } bool isValid() const { return coreIndex() != -1; } @@ -147,6 +160,7 @@ public: bool isOverridden() const { return _flags.isOverridden; } bool isDirect() const { return _flags.isDirect; } bool hasAccessors() const { return accessors() != nullptr; } + bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; } bool isFunction() const { return _flags.type == Flags::FunctionType; } bool isQObject() const { return _flags.type == Flags::QObjectDerivedType; } bool isEnum() const { return _flags.type == Flags::EnumType; } @@ -226,8 +240,17 @@ public: _metaObjectOffset = qint16(off); } - QQmlAccessors *accessors() const { return _accessors; } - void setAccessors(QQmlAccessors *acc) { _accessors = acc; } + QQmlAccessors *accessors() const { return nullptr; } // TODO: remove in subsequent patch + + StaticMetaCallFunction staticMetaCallFunction() const { return _staticMetaCallFunction; } + void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex) + { + if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) { + _flags._otherBits = relativePropertyIndex; + _staticMetaCallFunction = f; + } + } + quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return _flags._otherBits; } private: Flags _flags; @@ -243,7 +266,7 @@ private: qint16 _metaObjectOffset; QQmlPropertyCacheMethodArguments *_arguments; - QQmlAccessors *_accessors; + StaticMetaCallFunction _staticMetaCallFunction; friend class QQmlPropertyData; friend class QQmlPropertyCache; @@ -286,22 +309,24 @@ public: inline void readPropertyWithArgs(QObject *target, void *args[]) const { - if (hasAccessors()) { - accessors()->read(target, args[0]); - } else { + if (hasStaticMetaCallFunction()) + staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args); + else if (isDirect()) + target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args); + else QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args); - } } bool writeProperty(QObject *target, void *value, WriteFlags flags) const { - if (flags.testFlag(BypassInterceptor) && hasAccessors() && accessors()->write) { - accessors()->write(target, value); - } else { - int status = -1; - void *argv[] = { value, 0, &status, &flags }; + int status = -1; + void *argv[] = { value, 0, &status, &flags }; + if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction()) + staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv); + else if (flags.testFlag(BypassInterceptor) && isDirect()) + target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv); + else QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv); - } return true; } @@ -568,7 +593,8 @@ public: }; QQmlPropertyRawData::Flags::Flags() - : isConstant(false) + : _otherBits(0) + , isConstant(false) , isWritable(false) , isResettable(false) , isAlias(false) @@ -587,7 +613,6 @@ QQmlPropertyRawData::Flags::Flags() , isConstructor(false) , notFullyResolved(false) , overrideIndexIsProperty(false) - , _padding(0) {} bool QQmlPropertyRawData::Flags::operator==(const QQmlPropertyRawData::Flags &other) const @@ -635,7 +660,7 @@ QQmlPropertyData::QQmlPropertyData() setRevision(0); setMetaObjectOffset(-1); setArguments(nullptr); - setAccessors(nullptr); + trySetStaticMetaCallFunction(nullptr, 0); } QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d) @@ -645,7 +670,7 @@ QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d) bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other) { - return _flags == other._flags && + return flags() == other.flags() && propType() == other.propType() && coreIndex() == other.coreIndex() && notifyIndex() == other.notifyIndex() && @@ -752,7 +777,7 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const { - return (data->hasAccessors() || (data->metaObjectOffset() == -1 && data->revision() == 0)) || + return (data->metaObjectOffset() == -1 && data->revision() == 0) || (allowedRevisionCache[data->metaObjectOffset()] >= data->revision()); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index fd36f76d0e..5d70b17ece 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -42,6 +42,7 @@ #include <QtQml/qqmlcomponent.h> #include <private/qqmlengine_p.h> #include <private/qqmlcomponent_p.h> +#include <private/qqmlloggingcategory_p.h> #include <private/qqmlstringconverters_p.h> #include <private/qqmllocale_p.h> #include <private/qv8engine_p.h> @@ -76,6 +77,8 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qloggingcategory.h> +#include <QDebug> + QT_BEGIN_NAMESPACE using namespace QV4; @@ -1491,11 +1494,26 @@ static QString jsStack(QV4::ExecutionEngine *engine) { static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx, bool printStack = false) { + QLoggingCategory *loggingCategory = 0; QString result; QV4::ExecutionEngine *v4 = ctx->d()->engine; - for (int i = 0; i < ctx->argc(); ++i) { - if (i != 0) + int start = 0; + if (ctx->argc() > 0) { + if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) { + if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) { + if (category->category()) + loggingCategory = category->category(); + else + V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name"); + start = 1; + } + } + } + + + for (int i = start; i < ctx->argc(); ++i) { + if (i != start) result.append(QLatin1Char(' ')); if (ctx->args()[i].as<ArrayObject>()) @@ -1510,7 +1528,8 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c static QLoggingCategory qmlLoggingCategory("qml"); static QLoggingCategory jsLoggingCategory("js"); - QLoggingCategory *loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory; + if (!loggingCategory) + loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); const QByteArray baFunction = frame.function.toUtf8(); diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc index bbc64f1484..9ce26e1bb8 100644 --- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc @@ -150,7 +150,7 @@ develpoment files are present. In practice this currently means Visual Studio The adaptation is available both in normal, OpenGL-enabled Qt builds and also when Qt was configured with \c{-no-opengl}. However, it is never the default, meaning the user or the application has to explicitly request it by setting the -\c{QT_QUICK_BACKEND} environment variable or by calling +\c{QT_QUICK_BACKEND} environment variable to \c{d3d12} or by calling QQuickWindow::setSceneGraphBackend(). \section2 Motivation @@ -165,7 +165,7 @@ vendor-supported solution. This means that there are fewer problems anticipated with drivers, operations like window resizes, and special events like graphics device loss caused by device resets or graphics driver updates. -Peformance-wise the general expectation is a somewhat lower CPU usage compared +Performance-wise the general expectation is a somewhat lower CPU usage compared to OpenGL due to lower driver overhead, and a higher GPU utilization with less wasted idle time. The backend does not heavily utilize threads yet, which means there are opportunities for further improvements in the future, for example to diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index cfb62ee052..b526c8320d 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -126,8 +126,8 @@ public: struct State { State() - : strokeStyle(QColor("#000000")) - , fillStyle(QColor("#000000")) + : strokeStyle(QColor(Qt::black)) + , fillStyle(QColor(Qt::black)) , fillPatternRepeatX(false) , fillPatternRepeatY(false) , strokePatternRepeatX(false) diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp index d8147a48a5..857cd44b15 100644 --- a/src/quick/items/qquickframebufferobject.cpp +++ b/src/quick/items/qquickframebufferobject.cpp @@ -44,6 +44,7 @@ #include <private/qquickitem_p.h> #include <QSGSimpleTextureNode> +#include <QSGRendererInterface> QT_BEGIN_NAMESPACE @@ -260,6 +261,12 @@ public: int devicePixelRatio; }; +static inline bool isOpenGL(QSGRenderContext *rc) +{ + QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc); + return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL; +} + /*! * \internal */ @@ -278,6 +285,8 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode Q_D(QQuickFramebufferObject); if (!n) { + if (!isOpenGL(d->sceneGraphRenderContext())) + return 0; if (!d->node) d->node = new QSGFramebufferObjectNode; n = d->node; @@ -360,6 +369,8 @@ QSGTextureProvider *QQuickFramebufferObject::textureProvider() const qWarning("QQuickFramebufferObject::textureProvider: can only be queried on the rendering thread of an exposed window"); return 0; } + if (!isOpenGL(d->sceneGraphRenderContext())) + return 0; if (!d->node) d->node = new QSGFramebufferObjectNode; return d->node; diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp index 223976c32f..9e747f2c47 100644 --- a/src/quick/items/qquickrectangle.cpp +++ b/src/quick/items/qquickrectangle.cpp @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE QQuickPen::QQuickPen(QObject *parent) : QObject(parent) , m_width(1) - , m_color("#000000") + , m_color(Qt::black) , m_aligned(true) , m_valid(false) { diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index a54d6daf9c..c72565b2f4 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2247,8 +2247,12 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo me->accept(); q->sendEvent(item, me); if (me->isAccepted()) { - if (!q->mouseGrabberItem()) + auto mouseGrabber = q->mouseGrabberItem(); + if (mouseGrabber && mouseGrabber != item) { + item->mouseUngrabEvent(); + } else { item->grabMouse(); + } point->setAccepted(true); } return me->isAccepted(); diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 43cf1c28ab..899278843e 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -139,7 +139,8 @@ public Q_SLOTS: void textureFactoryDestroyed(QObject *o); protected: - QSGContext *m_sg; + // Hold m_sg with QPointer in the rare case it gets deleted before us. + QPointer<QSGContext> m_sg; QMutex m_mutex; QHash<QQuickTextureFactory *, QSGTexture *> m_textures; diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 7c2663d5a3..3501f30487 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -41,6 +41,7 @@ #include <private/qsgmaterialshader_p.h> #include <qopenglshaderprogram.h> +#include <qopenglframebufferobject.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -210,6 +211,7 @@ public: void activate(); void deactivate(); + bool useSRGB() const; uint m_useSRGB : 1; }; @@ -229,11 +231,26 @@ void QSG24BitTextMaskShader::initialize() } } +bool QSG24BitTextMaskShader::useSRGB() const +{ +#ifdef Q_OS_MACOS + if (!m_useSRGB) + return false; + + // m_useSRGB is true, but if some QOGLFBO was bound check it's texture format: + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLFramebufferObject *qfbo = QOpenGLContextPrivate::get(ctx)->qgl_current_fbo; + return !qfbo || qfbo->format().internalTextureFormat() == GL_SRGB8_ALPHA8_EXT; +#else + return m_useSRGB; +#endif +} + void QSG24BitTextMaskShader::activate() { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); funcs->glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); - if (m_useSRGB) + if (useSRGB()) funcs->glEnable(GL_FRAMEBUFFER_SRGB); } @@ -241,7 +258,7 @@ void QSG24BitTextMaskShader::deactivate() { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - if (m_useSRGB) + if (useSRGB()) funcs->glDisable(GL_FRAMEBUFFER_SRGB); } @@ -266,7 +283,7 @@ void QSG24BitTextMaskShader::updateState(const RenderState &state, QSGMaterial * if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = material->color(); - if (m_useSRGB) + if (useSRGB()) color = qt_sRGB_to_linear_RGB(color); QOpenGLContext::currentContext()->functions()->glBlendColor(color.x(), color.y(), color.z(), color.w()); color = qsg_premultiply(color, state.opacity()); diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 4fcc81fb18..6f10611ba3 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -70,6 +70,9 @@ QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context) */ void QSGDefaultRenderContext::initialize(void *context) { + if (!m_sg) + return; + QOpenGLContext *openglContext = static_cast<QOpenGLContext *>(context); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); @@ -163,7 +166,8 @@ void QSGDefaultRenderContext::invalidate() m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant()); m_gl = 0; - m_sg->renderContextInvalidated(this); + if (m_sg) + m_sg->renderContextInvalidated(this); emit invalidated(); } diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index cd55ae191d..7163fd8cff 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -2154,6 +2154,15 @@ void tst_QJSEngine::jsNumberClass() QJSValue ret = eng.evaluate("new Number(123).toPrecision()"); QVERIFY(ret.isString()); QCOMPARE(ret.toString(), QString::fromLatin1("123")); + ret = eng.evaluate("new Number(42).toPrecision(1)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("4e+1")); + ret = eng.evaluate("new Number(42).toPrecision(2)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("42")); + ret = eng.evaluate("new Number(42).toPrecision(3)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("42.0")); } } diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml new file mode 100644 index 0000000000..d19b6ecc41 --- /dev/null +++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +Item { + id:root + + LoggingCategory { + id: testCategory + name: "qt.test" + } + + LoggingCategory { + id: emptyCategory + } + + Component.onCompleted: { + console.debug(testCategory, "console.debug"); + console.log(testCategory, "console.log"); + console.info(testCategory, "console.info"); + console.warn(testCategory, "console.warn"); + console.error(testCategory, "console.error"); + + testCategory.name = "qt.test2"; + + console.error(emptyCategory, "console.error"); + } +} diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index f12656c5fe..f832143935 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -40,6 +40,7 @@ public: private slots: void logging(); + void categorized_logging(); void tracing(); void profiling(); void testAssert(); @@ -87,6 +88,41 @@ void tst_qqmlconsole::logging() delete object; } +void tst_qqmlconsole::categorized_logging() +{ + QUrl testUrl = testFileUrl("categorized_logging.qml"); + QQmlTestMessageHandler messageHandler; + messageHandler.setIncludeCategoriesEnabled(true); + + QLoggingCategory testCategory("qt.test"); + testCategory.setEnabled(QtDebugMsg, true); + QVERIFY(testCategory.isDebugEnabled()); + QVERIFY(testCategory.isWarningEnabled()); + QVERIFY(testCategory.isCriticalEnabled()); + + QQmlComponent component(&engine, testUrl); + QObject *object = component.create(); + QVERIFY2(object != 0, component.errorString().toUtf8()); + + QVERIFY(messageHandler.messages().contains("qt.test: console.info")); + QVERIFY(messageHandler.messages().contains("qt.test: console.warn")); + QVERIFY(messageHandler.messages().contains("qt.test: console.error")); + + QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"; + QVERIFY(messageHandler.messages().contains(emptyCategory)); + + QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created"; + QVERIFY(messageHandler.messages().contains(changedCategory)); + + QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(63) + + "Error: A QmlLoggingCatgory was provided without a valid name"; + QVERIFY(messageHandler.messages().contains(useEmptyCategory)); + + delete object; +} + void tst_qqmlconsole::tracing() { QUrl testUrl = testFileUrl("tracing.qml"); diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp index ab5e958323..124a107a37 100644 --- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp +++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp @@ -80,6 +80,10 @@ void tst_qqmlextensionplugin::iidCheck_data() QList<QString> files; for (QDirIterator it(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath), QDirIterator::Subdirectories); it.hasNext(); ) { QString file = it.next(); +#if defined(Q_OS_DARWIN) + if (file.contains(QLatin1String(".dSYM/"))) + continue; +#endif if (file.endsWith(SUFFIX)) { files << file; } @@ -105,7 +109,7 @@ void tst_qqmlextensionplugin::iidCheck() QFETCH(QString, filePath); QPluginLoader loader(filePath); - QVERIFY(loader.load()); + QVERIFY2(loader.load(), qPrintable(loader.errorString())); QVERIFY(loader.instance() != Q_NULLPTR); if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) { diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 7baff93574..b69c6eedf8 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -125,6 +125,7 @@ private slots: void containsPress_data(); void containsPress(); void ignoreBySource(); + void notPressedAfterStolenGrab(); private: int startDragDistance() const { @@ -1987,6 +1988,23 @@ void tst_QQuickMouseArea::ignoreBySource() QCOMPARE(flickable->contentY(), 0.); } +void tst_QQuickMouseArea::notPressedAfterStolenGrab() +{ + QQuickWindow window; + window.resize(200, 200); + window.show(); + QTest::qWaitForWindowExposed(&window); + + QQuickMouseArea *ma = new QQuickMouseArea(window.contentItem()); + ma->setSize(window.size()); + QObject::connect(ma, + static_cast<void (QQuickMouseArea::*)(QQuickMouseEvent*)>(&QQuickMouseArea::pressed), + [&]() { window.contentItem()->grabMouse(); }); + + QTest::mouseClick(&window, Qt::LeftButton); + QVERIFY(!ma->pressed()); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" diff --git a/tests/auto/shared/util.cpp b/tests/auto/shared/util.cpp index 55041eeb4d..96beb51612 100644 --- a/tests/auto/shared/util.cpp +++ b/tests/auto/shared/util.cpp @@ -101,11 +101,15 @@ Q_GLOBAL_STATIC(QMutex, qQmlTestMessageHandlerMutex) QQmlTestMessageHandler *QQmlTestMessageHandler::m_instance = 0; -void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &, const QString &message) +void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message) { QMutexLocker locker(qQmlTestMessageHandlerMutex()); - if (QQmlTestMessageHandler::m_instance) - QQmlTestMessageHandler::m_instance->m_messages.push_back(message); + if (QQmlTestMessageHandler::m_instance) { + if (QQmlTestMessageHandler::m_instance->m_includeCategories) + QQmlTestMessageHandler::m_instance->m_messages.push_back(QString("%1: %2").arg(context.category, message)); + else + QQmlTestMessageHandler::m_instance->m_messages.push_back(message); + } } QQmlTestMessageHandler::QQmlTestMessageHandler() @@ -114,6 +118,7 @@ QQmlTestMessageHandler::QQmlTestMessageHandler() Q_ASSERT(!QQmlTestMessageHandler::m_instance); QQmlTestMessageHandler::m_instance = this; m_oldHandler = qInstallMessageHandler(messageHandler); + m_includeCategories = false; } QQmlTestMessageHandler::~QQmlTestMessageHandler() diff --git a/tests/auto/shared/util.h b/tests/auto/shared/util.h index 47a4aae231..33d7cbd1d0 100644 --- a/tests/auto/shared/util.h +++ b/tests/auto/shared/util.h @@ -87,12 +87,15 @@ public: void clear() { m_messages.clear(); } + void setIncludeCategoriesEnabled(bool enabled) { m_includeCategories = enabled; } + private: - static void messageHandler(QtMsgType, const QMessageLogContext &, const QString &message); + static void messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message); static QQmlTestMessageHandler *m_instance; QStringList m_messages; QtMessageHandler m_oldHandler; + bool m_includeCategories; }; #endif // QQMLTESTUTILS_H |