diff options
455 files changed, 13756 insertions, 7001 deletions
diff --git a/.gitmodules b/.gitmodules index 9f78879479..881629497e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "tests/manual/v4/test262"] path = tests/manual/v4/test262 - url = git://github.com/tronical/test262.git + url = ../qtdeclarative-testsuites.git update = none diff --git a/.qmake.conf b/.qmake.conf index 58db72c7b1..fc13c75da5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.5.1 +MODULE_VERSION = 5.6.0 diff --git a/examples/quick/imageresponseprovider/ImageResponseProviderCore/qmldir b/examples/quick/imageresponseprovider/ImageResponseProviderCore/qmldir new file mode 100644 index 0000000000..3a5821bdf2 --- /dev/null +++ b/examples/quick/imageresponseprovider/ImageResponseProviderCore/qmldir @@ -0,0 +1,2 @@ +plugin qmlimageresponseproviderplugin + diff --git a/examples/quick/imageresponseprovider/doc/src/imageresponseprovider.qdoc b/examples/quick/imageresponseprovider/doc/src/imageresponseprovider.qdoc new file mode 100644 index 0000000000..afe1d406d8 --- /dev/null +++ b/examples/quick/imageresponseprovider/doc/src/imageresponseprovider.qdoc @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Canonical Limited and/or its subsidiary(-ies) +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title C++ Extensions: Image Response Provider Example + \example imageresponseprovider + + This examples shows how to use QQuickImageProvider to serve images + asynchronously to QML image elements. +*/ + diff --git a/examples/quick/imageresponseprovider/imageresponseprovider-example.qml b/examples/quick/imageresponseprovider/imageresponseprovider-example.qml new file mode 100644 index 0000000000..20c1e69434 --- /dev/null +++ b/examples/quick/imageresponseprovider/imageresponseprovider-example.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Canonical Limited and/or its subsidiary(-ies) +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import "ImageResponseProviderCore" + +Column { + Image { source: "image://async/slow" } + Image { source: "image://async/fast" } +} + diff --git a/examples/quick/imageresponseprovider/imageresponseprovider.cpp b/examples/quick/imageresponseprovider/imageresponseprovider.cpp new file mode 100644 index 0000000000..bdec29114b --- /dev/null +++ b/examples/quick/imageresponseprovider/imageresponseprovider.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Canonical Limited and/or its subsidiary(-ies) +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qqmlextensionplugin.h> + +#include <qqmlengine.h> +#include <qquickimageprovider.h> +#include <QDebug> +#include <QImage> +#include <QThreadPool> + +class AsyncImageResponse : public QQuickImageResponse, public QRunnable +{ + public: + AsyncImageResponse(const QString &id, const QSize &requestedSize) + : m_id(id), m_requestedSize(requestedSize), m_texture(0) + { + setAutoDelete(false); + } + + QQuickTextureFactory *textureFactory() const + { + return m_texture; + } + + void run() + { + QImage image(50, 50, QImage::Format_RGB32); + if (m_id == "slow") { + qDebug() << "Slow, red, sleeping for 5 seconds"; + QThread::sleep(5); + image.fill(Qt::red); + } else { + qDebug() << "Fast, blue, sleeping for 1 second"; + QThread::sleep(1); + image.fill(Qt::blue); + } + if (m_requestedSize.isValid()) + image = image.scaled(m_requestedSize); + m_texture = QQuickTextureFactory::textureFactoryForImage(image); + emit finished(); + } + + QString m_id; + QSize m_requestedSize; + QQuickTextureFactory *m_texture; +}; + +class AsyncImageProvider : public QQuickAsyncImageProvider +{ +public: + QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) + { + AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize); + pool.start(response); + return response; + } + +private: + QThreadPool pool; +}; + + +class ImageProviderExtensionPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") +public: + void registerTypes(const char *uri) + { + Q_UNUSED(uri); + } + + void initializeEngine(QQmlEngine *engine, const char *uri) + { + Q_UNUSED(uri); + engine->addImageProvider("async", new AsyncImageProvider); + } + +}; + + +#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface" + +#include "imageresponseprovider.moc" diff --git a/examples/quick/imageresponseprovider/imageresponseprovider.pro b/examples/quick/imageresponseprovider/imageresponseprovider.pro new file mode 100644 index 0000000000..856ddde863 --- /dev/null +++ b/examples/quick/imageresponseprovider/imageresponseprovider.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +CONFIG += plugin +QT += qml quick + +DESTDIR = ImageResponseProviderCore +TARGET = qmlimageresponseproviderplugin + +SOURCES += imageresponseprovider.cpp + +EXAMPLE_FILES = imageresponseprovider-example.qml + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/imageresponseprovider/ImageResponseProviderCore +qml.files = ImageResponseProviderCore/qmldir +qml.path = $$[QT_INSTALL_EXAMPLES]/quick/imageresponseprovider/ImageResponseProviderCore +INSTALLS = target qml diff --git a/examples/quick/imageresponseprovider/imageresponseprovider.qmlproject b/examples/quick/imageresponseprovider/imageresponseprovider.qmlproject new file mode 100644 index 0000000000..2bb4016996 --- /dev/null +++ b/examples/quick/imageresponseprovider/imageresponseprovider.qmlproject @@ -0,0 +1,14 @@ +import QmlProject 1.0 + +Project { + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } +} diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro index a412c53a65..c5ef46173c 100644 --- a/examples/quick/quick.pro +++ b/examples/quick/quick.pro @@ -20,6 +20,7 @@ SUBDIRS = quick-accessibility \ tutorials \ customitems \ imageprovider \ + imageresponseprovider \ window \ particles \ demos \ diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp index 8ef975c5b6..2834b93e10 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.cpp +++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp @@ -97,6 +97,7 @@ void Squircle::sync() } m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio()); m_renderer->setT(m_t); + m_renderer->setWindow(window()); } //! [9] @@ -156,5 +157,9 @@ void SquircleRenderer::paint() m_program->disableAttributeArray(0); m_program->release(); + + // Not strictly needed for this example, but generally useful for when + // mixing with raw OpenGL. + m_window->resetOpenGLState(); } //! [5] diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h index f797d7a7a5..28016def44 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.h +++ b/examples/quick/scenegraph/openglunderqml/squircle.h @@ -50,6 +50,7 @@ public: void setT(qreal t) { m_t = t; } void setViewportSize(const QSize &size) { m_viewportSize = size; } + void setWindow(QQuickWindow *window) { m_window = window; } public slots: void paint(); @@ -58,6 +59,7 @@ private: QSize m_viewportSize; qreal m_t; QOpenGLShaderProgram *m_program; + QQuickWindow *m_window; }; //! [1] diff --git a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h index 03f8e2d71a..734e779c70 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h @@ -359,6 +359,12 @@ public: } } + void mul32(Address src, RegisterID dest) + { + load32(src, dataTempRegister); + mul32(dataTempRegister, dest); + } + void neg32(RegisterID srcDest) { m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest); @@ -420,6 +426,12 @@ public: store32(dataTempRegister, dest.m_ptr); } + void or32(Address src, RegisterID dest) + { + load32(src, dataTempRegister); + or32(dataTempRegister, dest); + } + void rshift32(RegisterID shiftAmount, RegisterID dest) { m_assembler.srav(dest, dest, shiftAmount); @@ -615,6 +627,12 @@ public: m_assembler.xorInsn(dest, src, immTempRegister); } + void xor32(Address src, RegisterID dest) + { + load32(src, dataTempRegister); + xor32(dataTempRegister, dest); + } + void sqrtDouble(FPRegisterID src, FPRegisterID dst) { m_assembler.sqrtd(dst, src); @@ -2519,6 +2537,18 @@ public: m_assembler.cvtdw(dest, fpTempRegister); } + void convertUInt32ToDouble(RegisterID src, FPRegisterID dest, RegisterID scratch) + { + m_assembler.mtc1(src, fpTempRegister); + m_assembler.bltz(src, 2); + m_assembler.cvtdw(dest, fpTempRegister); + m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 4); + m_assembler.lui(scratch, 0x4f80); + m_assembler.mtc1(scratch, fpTempRegister); + m_assembler.cvtds(fpTempRegister, fpTempRegister); + m_assembler.addd(dest, dest, fpTempRegister); + } + void convertFloatToDouble(FPRegisterID src, FPRegisterID dst) { m_assembler.cvtds(dst, src); @@ -2761,7 +2791,7 @@ public: return CodeLocationLabel(); } - static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue) + static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*) { UNREACHABLE_FOR_PLATFORM(); } diff --git a/src/3rdparty/masm/disassembler/Mips32Disassembler.cpp b/src/3rdparty/masm/disassembler/Mips32Disassembler.cpp new file mode 100644 index 0000000000..af0a73b2cb --- /dev/null +++ b/src/3rdparty/masm/disassembler/Mips32Disassembler.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Cisco Systems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Disassembler.h" + +#if USE(MIPS32_DISASSEMBLER) + +#include "mips32/Mips32Opcode.h" +#include "MacroAssemblerCodeRef.h" + +namespace JSC { + +bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out) +{ + Mips32Opcode mipsOpcode; + + uint32_t* currentPC = reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(codePtr.executableAddress()) & ~3); + uint32_t* endPC = currentPC + (size / sizeof(uint32_t)); + + while (currentPC < endPC) { + char pcString[12]; + snprintf(pcString, sizeof(pcString), "0x%x", reinterpret_cast<unsigned>(currentPC)); + out.printf("%s%10s: %s\n", prefix, pcString, mipsOpcode.disassemble(currentPC)); + currentPC++; + } + + return true; +} + +} // namespace JSC + +#endif // USE(MIPS32_DISASSEMBLER) + diff --git a/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.cpp b/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.cpp new file mode 100644 index 0000000000..164217eb55 --- /dev/null +++ b/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.cpp @@ -0,0 +1,620 @@ +/* + * Copyright (C) 2015 Cisco Systems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(MIPS32_DISASSEMBLER) + +#include "Mips32Opcode.h" + +#include <stdio.h> + +#define OPCODE_FMT "%s\t" +#define COP1_OPCODE_FMT "%s.%s\t" +#define FORMAT_INSTR(_format, ...) \ + snprintf(m_formatBuffer, bufferSize - 1, _format, ##__VA_ARGS__) + +const char *Mips32Opcode::registerName(uint8_t r) +{ + static const char *gpRegisters[] = { + "zero", "AT", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "kt0", "kt1", "gp", "sp", "s8", "ra" + }; + + return (r < sizeof(gpRegisters)) ? gpRegisters[r] : "invalid"; +} + +const char *Mips32Opcode::fpRegisterName(uint8_t r) +{ + static const char *fpRegisters[] = { + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" + }; + + return (r < sizeof(fpRegisters)) ? fpRegisters[r] : "invalid"; +} + +void Mips32Opcode::formatSpecialEncodingOpcode(uint8_t op1, uint8_t op2, uint8_t dest, uint8_t shift, uint8_t function) +{ + const char *opcode; + OpcodePrintFormat format = Unknown; + switch (function) { + case 0x00: + format = RdRtSa; + opcode = "sll"; + break; + case 0x02: + format = RdRtSa; + opcode = "srl"; + break; + case 0x03: + format = RdRtSa; + opcode = "sra"; + break; + case 0x04: + format = RdRtRs; + opcode = "sllv"; + break; + case 0x06: + format = RdRtRs; + opcode = "srlv"; + break; + case 0x07: + format = RdRtRs; + opcode = "srav"; + break; + case 0x08: + format = Rs; + opcode = "jr"; + break; + case 0x09: + format = (dest != 0x1f) ? RdRs : Rs; + opcode = "jalr"; + break; + case 0x10: + format = Rd; + opcode = "mfhi"; + break; + case 0x11: + format = Rs; + opcode = "mthi"; + break; + case 0x12: + format = Rd; + opcode = "mflo"; + break; + case 0x13: + format = Rs; + opcode = "mtlo"; + break; + case 0x18: + format = RsRt; + opcode = "mult"; + break; + case 0x19: + format = RsRt; + opcode = "multu"; + break; + case 0x1a: + format = RsRt; + opcode = "div"; + break; + case 0x1b: + format = RsRt; + opcode = "divu"; + break; + case 0x20: + format = RdRsRt; + opcode = "add"; + break; + case 0x21: + if (op2) { + format = RdRsRt; + opcode = "addu"; + } else { + format = RdRs; + opcode = "move"; + } + break; + case 0x22: + format = RdRsRt; + opcode = "sub"; + break; + case 0x23: + format = RdRsRt; + opcode = "subu"; + break; + case 0x24: + format = RdRsRt; + opcode = "and"; + break; + case 0x25: + format = RdRsRt; + opcode = "or"; + break; + case 0x26: + format = RdRsRt; + opcode = "xor"; + break; + case 0x27: + format = RdRsRt; + opcode = "nor"; + break; + case 0x2a: + format = RdRsRt; + opcode = "slt"; + break; + case 0x2b: + format = RdRsRt; + opcode = "sltu"; + break; + } + + switch (format) { + case Rs: + FORMAT_INSTR(OPCODE_FMT "%s", opcode, registerName(op1)); + break; + case Rd: + FORMAT_INSTR(OPCODE_FMT "%s", opcode, registerName(dest)); + break; + case RdRs: + FORMAT_INSTR(OPCODE_FMT "%s, %s", opcode, registerName(dest), registerName(op1)); + break; + case RsRt: + FORMAT_INSTR(OPCODE_FMT "%s, %s", opcode, registerName(op1), registerName(op2)); + break; + case RdRtRs: + FORMAT_INSTR(OPCODE_FMT "%s, %s, %s", opcode, registerName(dest), registerName(op2), registerName(op1)); + break; + case RdRsRt: + FORMAT_INSTR(OPCODE_FMT "%s, %s, %s", opcode, registerName(dest), registerName(op1), registerName(op2)); + break; + case RdRtSa: + FORMAT_INSTR(OPCODE_FMT "%s, %s, %d", opcode, registerName(dest), registerName(op2), shift); + break; + default: + FORMAT_INSTR("unknown special encoding opcode 0x%x", function); + break; + } +} + +void Mips32Opcode::formatSpecial2EncodingOpcode(uint8_t op1, uint8_t op2, uint8_t dest, uint8_t function) +{ + if (function == 0x02) { + FORMAT_INSTR(OPCODE_FMT "%s, %s, %s", "mul", registerName(dest), registerName(op1), registerName(op2)); + return; + } + + FORMAT_INSTR("unknown special2 encoding opcode 0x%x", function); +} + +void Mips32Opcode::formatJumpEncodingOpcode(uint32_t iOp, uint32_t index, uint32_t* opcodePtr) +{ + if ((iOp != 0x02) && (iOp != 0x03)) { + FORMAT_INSTR("unknown jump encoding opcode 0x%x", iOp); + return; + } + + FORMAT_INSTR(OPCODE_FMT "0x%x", (iOp == 0x02) ? "j" : "jal", + (reinterpret_cast<unsigned>(opcodePtr+1) & 0xf0000000) | (index << 2)); +} + +void Mips32Opcode::formatREGIMMEncodingOpcode(uint8_t rs, uint8_t rt, int16_t imm, uint32_t* opcodePtr) +{ + const char *opcodes[] = { "bltz", "bgez", "bltzl", "bgezl" }; + if (rt < sizeof(opcodes)) + FORMAT_INSTR(OPCODE_FMT "%s, 0x%x", opcodes[rt], registerName(rs), reinterpret_cast<unsigned>(opcodePtr+1) + (imm << 2)); + else + FORMAT_INSTR("unknown REGIMM encoding opcode 0x%x", rt); +} + +void Mips32Opcode::formatImmediateEncodingOpcode(uint32_t iOp, uint8_t rs, uint8_t rt, int16_t imm, uint32_t* opcodePtr) +{ + const char *opcode; + OpcodePrintFormat format = Unknown; + switch (iOp) { + case 0x04: + if (!rs && !rt) { + format = Addr; + opcode = "b"; + } else { + format = RsRtAddr; + opcode = "beq"; + } + break; + case 0x05: + format = RsRtAddr; + opcode = "bne"; + break; + case 0x06: + format = RsRtAddr; + opcode = "blez"; + break; + case 0x07: + format = RsRtAddr; + opcode = "bgtz"; + break; + case 0x08: + format = RtRsImm; + opcode = "addi"; + break; + case 0x09: + if (rs) { + format = RtRsImm; + opcode = "addiu"; + } else { + format = RtUImm; + opcode = "li"; + } + break; + case 0x0a: + format = RtRsImm; + opcode = "slti"; + break; + case 0x0b: + format = RtRsImm; + opcode = "sltiu"; + break; + case 0x0c: + format = RtRsImm; + opcode = "andi"; + break; + case 0x0d: + format = RtRsImm; + opcode = "ori"; + break; + case 0x0e: + format = RtRsImm; + opcode = "xori"; + break; + case 0x0f: + format = RtUImm; + opcode = "lui"; + break; + case 0x20: + format = RtOffsetBase; + opcode = "lb"; + break; + case 0x21: + format = RtOffsetBase; + opcode = "lh"; + break; + case 0x22: + format = RtOffsetBase; + opcode = "lwl"; + break; + case 0x23: + format = RtOffsetBase; + opcode = "lw"; + break; + case 0x24: + format = RtOffsetBase; + opcode = "lbu"; + break; + case 0x25: + format = RtOffsetBase; + opcode = "lhu"; + break; + case 0x26: + format = RtOffsetBase; + opcode = "lwr"; + break; + case 0x28: + format = RtOffsetBase; + opcode = "sb"; + break; + case 0x29: + format = RtOffsetBase; + opcode = "sh"; + break; + case 0x2a: + format = RtOffsetBase; + opcode = "swl"; + break; + case 0x2b: + format = RtOffsetBase; + opcode = "sw"; + break; + case 0x2e: + format = RtOffsetBase; + opcode = "swr"; + break; + case 0x35: + format = FtOffsetBase; + opcode = "ldc1"; + break; + case 0x3d: + format = FtOffsetBase; + opcode = "sdc1"; + break; + } + + switch (format) { + case Addr: + FORMAT_INSTR(OPCODE_FMT "0x%x", opcode, reinterpret_cast<unsigned>(opcodePtr+1) + (imm << 2)); + break; + case RtUImm: + FORMAT_INSTR(OPCODE_FMT "%s, 0x%hx", opcode, registerName(rt), imm); + break; + case RtRsImm: + FORMAT_INSTR(OPCODE_FMT "%s, %s, %d", opcode, registerName(rt), registerName(rs), imm); + break; + case RsRtAddr: + FORMAT_INSTR(OPCODE_FMT "%s, %s, 0x%x", opcode, registerName(rs), registerName(rt), + reinterpret_cast<unsigned>(opcodePtr+1) + (imm << 2)); + break; + case RtOffsetBase: + FORMAT_INSTR(OPCODE_FMT "%s, %d(%s)", opcode, registerName(rt), imm, registerName(rs)); + break; + case FtOffsetBase: + FORMAT_INSTR(OPCODE_FMT "%s, %d(%s)", opcode, fpRegisterName(rt), imm, registerName(rs)); + break; + default: + FORMAT_INSTR("unknown immediate encoding opcode 0x%x", iOp); + break; + } +} + +void Mips32Opcode::formatCOP1Opcode(uint8_t fmt, uint8_t ft, uint8_t fs, uint8_t fd, uint8_t func) +{ + const char *opcode; + const char *suffix; + OpcodePrintFormat format = Unknown; + + if (fmt < 0x10) { + switch (fmt) { + case 0x00: + opcode = "mfc1"; + break; + case 0x04: + opcode = "mtc1"; + break; + default: + FORMAT_INSTR("unknown COP1 rs 0x%x", fmt); + return; + } + FORMAT_INSTR(OPCODE_FMT "%s, %s", opcode, registerName(ft), fpRegisterName(fs)); + return; + } + + switch (fmt) { + case 0x10: + suffix = "s"; + break; + case 0x11: + suffix = "d"; + break; + case 0x14: + suffix = "w"; + break; + case 0x15: + suffix = "l"; + break; + case 0x16: + suffix = "ps"; + break; + default: + FORMAT_INSTR("unknown COP1 fmt 0x%x", fmt); + return; + } + + switch (func) { + case 0x00: + format = FdFsFt; + opcode = "add"; + break; + case 0x01: + format = FdFsFt; + opcode = "sub"; + break; + case 0x02: + format = FdFsFt; + opcode = "mul"; + break; + case 0x03: + format = FdFsFt; + opcode = "div"; + break; + case 0x04: + format = FdFs; + opcode = "sqrt"; + break; + case 0x05: + format = FdFs; + opcode = "abs"; + break; + case 0x06: + format = FdFs; + opcode = "mov"; + break; + case 0x07: + format = FdFs; + opcode = "neg"; + break; + case 0x08: + format = FdFs; + opcode = "round.l"; + break; + case 0x09: + format = FdFs; + opcode = "trunc.l"; + break; + case 0x0a: + format = FdFs; + opcode = "ceil.l"; + break; + case 0x0b: + format = FdFs; + opcode = "floor.l"; + break; + case 0x0c: + format = FdFs; + opcode = "round.w"; + break; + case 0x0d: + format = FdFs; + opcode = "trunc.w"; + break; + case 0x0e: + format = FdFs; + opcode = "ceil.w"; + break; + case 0x0f: + format = FdFs; + opcode = "floor.w"; + break; + case 0x20: + format = FdFs; + opcode = "cvt.s"; + break; + case 0x21: + format = FdFs; + opcode = "cvt.d"; + break; + case 0x24: + format = FdFs; + opcode = "cvt.w"; + break; + case 0x25: + format = FdFs; + opcode = "cvt.l"; + break; + } + + switch (format) { + case FdFs: + FORMAT_INSTR(COP1_OPCODE_FMT "%s, %s", opcode, suffix, fpRegisterName(fd), fpRegisterName(fs)); + break; + case FdFsFt: + FORMAT_INSTR(COP1_OPCODE_FMT "%s, %s, %s", opcode, suffix, fpRegisterName(fd), fpRegisterName(fs), fpRegisterName(ft)); + break; + default: + FORMAT_INSTR("unknown COP1 opcode 0x%x", func); + break; + } +} + +void Mips32Opcode::formatCOP1FPCompareOpcode(uint8_t fmt, uint8_t ft, uint8_t fs, uint8_t cc, uint8_t cond) +{ + const char *suffix; + static const char *opcodes[] = { + "c.f", "c.un", "c.eq", "c.ueq", "c.olt", "c.ult", "c.ole", "c.ule", + "c.sf", "c.ngle", "c.seq", "c.ngl", "c.lt", "c.nge", "c.le", "c.ngt" + }; + ASSERT(cond < sizeof(opcdoes)); + + switch (fmt) { + case 0x10: + suffix = "s"; + break; + case 0x11: + suffix = "d"; + break; + case 0x16: + suffix = "ps"; + break; + default: + FORMAT_INSTR("unknown COP1 fmt 0x%x", fmt); + return; + } + + if (!cc) + FORMAT_INSTR(COP1_OPCODE_FMT "%s, %s", opcodes[cond], suffix, fpRegisterName(fs), fpRegisterName(ft)); + else + FORMAT_INSTR(COP1_OPCODE_FMT "%d, %s, %s", opcodes[cond], suffix, cc, fpRegisterName(fs), fpRegisterName(ft)); +} + +void Mips32Opcode::formatCOP1BCOpcode(uint8_t cc, uint8_t ndtf, int16_t offset, uint32_t* opcodePtr) +{ + static const char *opcodes[] = { "bc1f", "bc1t", "bc1fl", "bc1tl" }; + ASSERT(ndtf < sizeof(opcodes)); + + if (!cc) + FORMAT_INSTR(OPCODE_FMT "0x%x", opcodes[ndtf], reinterpret_cast<unsigned>(opcodePtr+1) + (offset << 2)); + else + FORMAT_INSTR(OPCODE_FMT "%d, 0x%x", opcodes[ndtf], cc, reinterpret_cast<unsigned>(opcodePtr+1) + (offset << 2)); +} + +const char* Mips32Opcode::disassemble(uint32_t* opcodePtr) +{ + uint32_t opcode = *opcodePtr; + uint32_t iOp = (opcode >> 26) & 0x3f; + + if (!opcode) + FORMAT_INSTR(OPCODE_FMT, "nop"); + else if (!iOp) { + uint8_t op1 = (opcode >> 21) & 0x1f; + uint8_t op2 = (opcode >> 16) & 0x1f; + uint8_t dst = (opcode >> 11) & 0x1f; + uint8_t shft = (opcode >> 6) & 0x1f; + uint8_t func = opcode & 0x3f; + formatSpecialEncodingOpcode(op1, op2, dst, shft, func); + } else if ((iOp == 0x02) || (iOp == 0x03)) { + uint32_t index = opcode & 0x3ffffff; + formatJumpEncodingOpcode(iOp, index, opcodePtr); + } else if (iOp == 0x11) { + uint8_t fmt = (opcode >> 21) & 0x1f; + if (fmt == 0x08) { + uint8_t cc = (opcode >> 18) & 0x07; + uint8_t ndtf = (opcode >> 16) & 0x03; + int16_t offset = opcode & 0xffff; + formatCOP1BCOpcode(cc, ndtf, offset, opcodePtr); + } else if ((opcode & 0xf0) == 0x30) { + uint8_t ft = (opcode >> 16) & 0x1f; + uint8_t fs = (opcode >> 11) & 0x1f; + uint8_t cc = (opcode >> 8) & 0x07; + uint8_t cond = opcode & 0x0f; + formatCOP1FPCompareOpcode(fmt, ft, fs, cc, cond); + } else { + uint8_t ft = (opcode >> 16) & 0x1f; + uint8_t fs = (opcode >> 11) & 0x1f; + uint8_t fd = (opcode >> 6) & 0x1f; + uint8_t func = opcode & 0x3f; + formatCOP1Opcode(fmt, ft, fs, fd, func); + } + } else if (iOp == 0x1c) { + uint8_t op1 = (opcode >> 21) & 0x1f; + uint8_t op2 = (opcode >> 16) & 0x1f; + uint8_t dst = (opcode >> 11) & 0x1f; + uint8_t func = opcode & 0x3f; + formatSpecial2EncodingOpcode(op1, op2, dst, func); + } else { + uint8_t rs = (opcode >> 21) & 0x1f; + uint8_t rt = (opcode >> 16) & 0x1f; + int16_t imm = opcode & 0xffff; + if (iOp == 0x01) + formatREGIMMEncodingOpcode(rs, rt, imm, opcodePtr); + else + formatImmediateEncodingOpcode(iOp, rs, rt, imm, opcodePtr); + } + + return m_formatBuffer; +} + +#endif // USE(MIPS32_DISASSEMBLER) diff --git a/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.h b/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.h new file mode 100644 index 0000000000..c63fb1109a --- /dev/null +++ b/src/3rdparty/masm/disassembler/mips32/Mips32Opcode.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Cisco Systems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MIPS32Opcode_h_ +#define _MIPS32Opcode_h_ + +#if USE(MIPS32_DISASSEMBLER) + +#include <stdint.h> +#include <wtf/Assertions.h> + +class Mips32Opcode { +public: + Mips32Opcode() {} + + const char* disassemble(uint32_t*); + +private: + enum OpcodePrintFormat { + Unknown = 0, + Rs, + Rd, + Addr, + RdRs, + RsRt, + RtUImm, + RdRtRs, + RdRsRt, + RdRtSa, + RtRsImm, + RsRtAddr, + RtOffsetBase, + FdFs, + FdFsFt, + FtOffsetBase + }; + + const char *registerName(uint8_t r); + const char *fpRegisterName(uint8_t r); + void formatSpecialEncodingOpcode(uint8_t op1, uint8_t op2, uint8_t dest, uint8_t shift, uint8_t function); + void formatSpecial2EncodingOpcode(uint8_t op1, uint8_t op2, uint8_t dest, uint8_t function); + void formatJumpEncodingOpcode(uint32_t iOp, uint32_t index, uint32_t* opcodePtr); + void formatREGIMMEncodingOpcode(uint8_t rs, uint8_t rt, int16_t imm, uint32_t* opcodePtr); + void formatImmediateEncodingOpcode(uint32_t iOp, uint8_t rs, uint8_t rt, int16_t imm, uint32_t* opcodePtr); + void formatCOP1Opcode(uint8_t fmt, uint8_t ft, uint8_t fs, uint8_t fd, uint8_t func); + void formatCOP1FPCompareOpcode(uint8_t fmt, uint8_t ft, uint8_t fs, uint8_t cc, uint8_t cond); + void formatCOP1BCOpcode(uint8_t cc, uint8_t ndtf, int16_t offset, uint32_t* opcodePtr); + + static const int bufferSize = 81; + + char m_formatBuffer[bufferSize]; +}; + +#endif + +#endif // _MIPS32Opcode_h_ diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri index d0980c5312..f09a8329c9 100644 --- a/src/3rdparty/masm/masm-defs.pri +++ b/src/3rdparty/masm/masm-defs.pri @@ -26,6 +26,7 @@ INCLUDEPATH += $$PWD disassembler { if(isEqual(QT_ARCH, "i386")|isEqual(QT_ARCH, "x86_64")): DEFINES += WTF_USE_UDIS86=1 if(isEqual(QT_ARCH, "arm")): DEFINES += WTF_USE_ARMV7_DISASSEMBLER=1 + if(isEqual(QT_ARCH, "mips")): DEFINES += WTF_USE_MIPS32_DISASSEMBLER=1 } else { DEFINES += WTF_USE_UDIS86=0 } diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri index 3497650f0c..04548fe8a3 100644 --- a/src/3rdparty/masm/masm.pri +++ b/src/3rdparty/masm/masm.pri @@ -59,6 +59,9 @@ contains(DEFINES, WTF_USE_UDIS86=1) { SOURCES += $$PWD/disassembler/ARMv7Disassembler.cpp SOURCES += $$PWD/disassembler/ARMv7/ARMv7DOpcode.cpp HEADERS += $$PWD/disassembler/ARMv7/ARMv7DOpcode.h +SOURCES += $$PWD/disassembler/Mips32Disassembler.cpp +SOURCES += $$PWD/disassembler/mips32/Mips32Opcode.cpp +HEADERS += $$PWD/disassembler/mips32/Mips32Opcode.h SOURCES += $$PWD/yarr/*.cpp HEADERS += $$PWD/yarr/*.h diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h index 3e2a51379c..f0612fe50e 100644 --- a/src/3rdparty/masm/wtf/Platform.h +++ b/src/3rdparty/masm/wtf/Platform.h @@ -735,7 +735,7 @@ #define WTF_USE_UDIS86 1 #endif -#if !defined(ENABLE_DISASSEMBLER) && (USE(UDIS86) || USE(ARMV7_DISASSEMBLER)) +#if !defined(ENABLE_DISASSEMBLER) && (USE(UDIS86) || USE(ARMV7_DISASSEMBLER) || USE(MIPS32_DISASSEMBLER)) #define ENABLE_DISASSEMBLER 1 #endif diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp index e1db7834ec..532815e5c1 100644 --- a/src/imports/folderlistmodel/fileinfothread.cpp +++ b/src/imports/folderlistmodel/fileinfothread.cpp @@ -251,6 +251,7 @@ void FileInfoThread::getFileInfos(const QString &path) fileInfoList = currentDir.entryInfoList(nameFilters, filter, sortFlags); if (!fileInfoList.isEmpty()) { + filePropertyList.reserve(fileInfoList.count()); foreach (QFileInfo info, fileInfoList) { //qDebug() << "Adding file : " << info.fileName() << "to list "; filePropertyList << FileProperty(info); diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp index 80b32e64ef..0f4a5bda54 100644 --- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp @@ -788,6 +788,20 @@ QVariant QQuickFolderListModel::get(int idx, const QString &property) const return QVariant(); } +/*! + \qmlmethod int FolderListModel::indexOf(url file) + \since 5.6 + + Get the index of the given file URL if the model contains it, + or -1 if not. +*/ +int QQuickFolderListModel::indexOf(const QUrl &file) const +{ + Q_D(const QQuickFolderListModel); + FileProperty toFind(QFileInfo(file.toLocalFile())); + return d->data.indexOf(toFind); +} + #include "moc_qquickfolderlistmodel.cpp" //![code] diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h index 63ed528556..fcfec56c87 100644 --- a/src/imports/folderlistmodel/qquickfolderlistmodel.h +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h @@ -109,9 +109,9 @@ public: void setNameFilters(const QStringList &filters); enum SortField { Unsorted, Name, Time, Size, Type }; + Q_ENUM(SortField) SortField sortField() const; void setSortField(SortField field); - Q_ENUMS(SortField) bool sortReversed() const; void setSortReversed(bool rev); @@ -132,6 +132,7 @@ public: Q_INVOKABLE bool isFolder(int index) const; Q_INVOKABLE QVariant get(int idx, const QString &property) const; + Q_INVOKABLE int indexOf(const QUrl &file) const; //![parserstatus] virtual void classBegin(); diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index b0ba3f9228..22a3eed39d 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -126,7 +126,7 @@ public: ~QQmlSqlDatabaseWrapper() { } - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; } @@ -214,7 +214,7 @@ static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV4::E return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName; } -static ReturnedValue qmlsqldatabase_rows_index(QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0) +static ReturnedValue qmlsqldatabase_rows_index(const QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0) { Scope scope(v4); @@ -238,15 +238,14 @@ static ReturnedValue qmlsqldatabase_rows_index(QQmlSqlDatabaseWrapper *r, Execut } } -ReturnedValue QQmlSqlDatabaseWrapper::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue QQmlSqlDatabaseWrapper::getIndexed(const Managed *m, uint index, bool *hasProperty) { - QV4::Scope scope(static_cast<QQmlSqlDatabaseWrapper *>(m)->engine()); Q_ASSERT(m->as<QQmlSqlDatabaseWrapper>()); - QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, static_cast<QQmlSqlDatabaseWrapper *>(m)); + const QQmlSqlDatabaseWrapper *r = static_cast<const QQmlSqlDatabaseWrapper *>(m); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows) return Object::getIndexed(m, index, hasProperty); - return qmlsqldatabase_rows_index(r, scope.engine, index, hasProperty); + return qmlsqldatabase_rows_index(r, r->engine(), index, hasProperty); } static ReturnedValue qmlsqldatabase_rows_item(CallContext *ctx) @@ -285,13 +284,13 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx) if (query.prepare(sql)) { if (ctx->argc() > 1) { ScopedValue values(scope, ctx->args()[1]); - if (values->asArrayObject()) { + if (values->as<ArrayObject>()) { ScopedArrayObject array(scope, values); quint32 size = array->getLength(); QV4::ScopedValue v(scope); for (quint32 ii = 0; ii < size; ++ii) query.bindValue(ii, scope.engine->toVariant((v = array->getIndexed(ii)), -1)); - } else if (values->asObject()) { + } else if (values->as<Object>()) { ScopedObject object(scope, values); ObjectIterator it(scope, object, ObjectIterator::WithProtoChain|ObjectIterator::EnumerableOnly); ScopedValue key(scope); @@ -304,7 +303,7 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx) if (key->isString()) { query.bindValue(key->stringValue()->toQString(), v); } else { - assert(key->isInteger()); + Q_ASSERT(key->isInteger()); query.bindValue(key->integerValue(), v); } } @@ -401,7 +400,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx) db.transaction(); ScopedCallData callData(scope, 1); - callData->thisObject = scope.engine->globalObject(); + callData->thisObject = scope.engine->globalObject; callData->args[0] = w; TransactionRollback rollbackOnException(&db, &w->d()->inTransaction); @@ -433,7 +432,7 @@ static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool re if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database) V4THROW_REFERENCE("Not a SQLDatabase object"); - FunctionObject *callback = ctx->argc() ? ctx->args()[0].asFunctionObject() : 0; + const FunctionObject *callback = ctx->argc() ? ctx->args()[0].as<FunctionObject>() : 0; if (!callback) V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr("transaction: missing callback")); @@ -450,7 +449,7 @@ static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool re db.transaction(); if (callback) { ScopedCallData callData(scope, 1); - callData->thisObject = scope.engine->globalObject(); + callData->thisObject = scope.engine->globalObject; callData->args[0] = w; TransactionRollback rollbackOnException(&db, &w->d()->inTransaction); callback->call(callData); @@ -673,7 +672,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) QString dbversion = (v = (*args)[1])->toQStringNoThrow(); QString dbdescription = (v = (*args)[2])->toQStringNoThrow(); int dbestimatedsize = (v = (*args)[3])->toInt32(); - FunctionObject *dbcreationCallback = (v = (*args)[4])->asFunctionObject(); + FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>(); QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(dbname.toUtf8()); @@ -724,7 +723,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) if (created && dbcreationCallback) { Scope scope(ctx); ScopedCallData callData(scope, 1); - callData->thisObject = scope.engine->globalObject(); + callData->thisObject = scope.engine->globalObject; callData->args[0] = db; dbcreationCallback->call(callData); } diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 039ee63f07..4c48611e79 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -613,12 +613,19 @@ Item { \li blue(x, y) Returns the blue channel value of the pixel at \a x, \a y position \li alpha(x, y) Returns the alpha channel value of the pixel at \a x, \a y position \li pixel(x, y) Returns the color value of the pixel at \a x, \a y position + \li equals(image) Returns \c true if this image is identical to \a image - + see \l QImage::operator== (since 5.6) + For example: \code var image = grabImage(rect); compare(image.red(10, 10), 255); compare(image.pixel(20, 20), Qt.rgba(255, 0, 0, 255)); + + rect.width += 10; + var newImage = grabImage(rect); + verify(!newImage.equals(image)); \endcode \endlist diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp index b078edcbc6..832f484c13 100644 --- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp +++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp @@ -36,7 +36,7 @@ #include <qqmlcontext.h> #include <private/qqmlengine_p.h> #include <private/qv8engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4engine_p.h> #include <private/qv4object_p.h> diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp index 32cde7c126..5e244ba02c 100644 --- a/src/particles/qquickcustomparticle.cpp +++ b/src/particles/qquickcustomparticle.cpp @@ -370,10 +370,10 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes() } } - NodeHashConstIt it = m_nodes.begin(); + NodeHashConstIt it = m_nodes.cbegin(); rootNode = it.value(); rootNode->setFlag(QSGNode::OwnsMaterial, true); - const NodeHashConstIt cend = m_nodes.end(); + NodeHashConstIt cend = m_nodes.cend(); for (++it; it != cend; ++it) rootNode->appendChildNode(it.value()); diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index c0e1b4e422..a17949130f 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1156,7 +1156,9 @@ QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datu QQuickParticleGroupData* gd = m_system->groupData[datum->group]; if (!m_shadowData.contains(datum->group)) { QVector<QQuickParticleData*> data; - for (int i=0; i<gd->size(); i++){ + const int gdSize = gd->size(); + data.reserve(gdSize); + for (int i = 0; i < gdSize; i++) { QQuickParticleData* datum = new QQuickParticleData(m_system); *datum = *(gd->data[i]); data << datum; diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h index 7d7d98dab6..16832d76dc 100644 --- a/src/particles/qquickimageparticle_p.h +++ b/src/particles/qquickimageparticle_p.h @@ -175,13 +175,12 @@ class QQuickImageParticle : public QQuickParticlePainter Q_PROPERTY(bool spritesInterpolate READ spritesInterpolate WRITE setSpritesInterpolate NOTIFY spritesInterpolateChanged) Q_PROPERTY(EntryEffect entryEffect READ entryEffect WRITE setEntryEffect NOTIFY entryEffectChanged) - Q_ENUMS(EntryEffect) - Q_ENUMS(Status) public: explicit QQuickImageParticle(QQuickItem *parent = 0); virtual ~QQuickImageParticle(); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) QQmlListProperty<QQuickSprite> sprites(); QQuickStochasticEngine* spriteEngine() {return m_spriteEngine;} @@ -191,6 +190,7 @@ public: Fade = 1, Scale = 2 }; + Q_ENUM(EntryEffect) enum PerformanceLevel{//TODO: Expose? Unknown = 0, diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h index 65e2a34aa7..68f01e3f6a 100644 --- a/src/particles/qquickparticleemitter_p.h +++ b/src/particles/qquickparticleemitter_p.h @@ -67,7 +67,6 @@ class QQuickParticleEmitter : public QQuickItem Q_PROPERTY(QQuickDirection *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged) Q_PROPERTY(qreal velocityFromMovement READ velocityFromMovement WRITE setVelocityFromMovement NOTIFY velocityFromMovementChanged) - Q_ENUMS(Lifetime) public: explicit QQuickParticleEmitter(QQuickItem *parent = 0); virtual ~QQuickParticleEmitter(); @@ -76,6 +75,7 @@ public: enum Lifetime { InfiniteLife = QQuickParticleSystem::maxLife }; + Q_ENUM(Lifetime) bool enabled() const { diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index affd19d981..617c33d6e5 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -1025,6 +1025,7 @@ void QQuickParticleSystem::createEngine() } m_groups = newList; QList<QQuickStochasticState*> states; + states.reserve(m_groups.count()); foreach (QQuickParticleGroup* g, m_groups) states << (QQuickStochasticState*)g; diff --git a/src/particles/qquickpointattractor_p.h b/src/particles/qquickpointattractor_p.h index aa2c9f2083..31038aeba4 100644 --- a/src/particles/qquickpointattractor_p.h +++ b/src/particles/qquickpointattractor_p.h @@ -45,8 +45,6 @@ class QQuickAttractorAffector : public QQuickParticleAffector Q_PROPERTY(qreal pointY READ pointY WRITE setPointY NOTIFY pointYChanged) Q_PROPERTY(AffectableParameters affectedParameter READ affectedParameter WRITE setAffectedParameter NOTIFY affectedParameterChanged) Q_PROPERTY(Proportion proportionalToDistance READ proportionalToDistance WRITE setProportionalToDistance NOTIFY proportionalToDistanceChanged) - Q_ENUMS(AffectableParameters) - Q_ENUMS(Proportion) public: enum Proportion{ @@ -56,12 +54,14 @@ public: InverseLinear, InverseQuadratic }; + Q_ENUM(Proportion) enum AffectableParameters { Position, Velocity, Acceleration }; + Q_ENUM(AffectableParameters) explicit QQuickAttractorAffector(QQuickItem *parent = 0); diff --git a/src/particles/qquicktrailemitter_p.h b/src/particles/qquicktrailemitter_p.h index d1213158d8..fd11a07056 100644 --- a/src/particles/qquicktrailemitter_p.h +++ b/src/particles/qquicktrailemitter_p.h @@ -48,11 +48,11 @@ class QQuickTrailEmitter : public QQuickParticleEmitter Q_PROPERTY(qreal emitHeight READ emitterYVariation WRITE setEmitterYVariation NOTIFY emitterYVariationChanged) Q_PROPERTY(qreal emitWidth READ emitterXVariation WRITE setEmitterXVariation NOTIFY emitterXVariationChanged) - Q_ENUMS(EmitSize) public: enum EmitSize { ParticleSize = -2//Anything less than 0 will do }; + Q_ENUM(EmitSize) explicit QQuickTrailEmitter(QQuickItem *parent = 0); virtual void emitWindow(int timeStamp); virtual void reset(); diff --git a/src/particles/qquickv4particledata_p.h b/src/particles/qquickv4particledata_p.h index f211ec7e7d..c29c7e1134 100644 --- a/src/particles/qquickv4particledata_p.h +++ b/src/particles/qquickv4particledata_p.h @@ -36,7 +36,7 @@ #include <private/qv8engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/particles/qquickwander_p.h b/src/particles/qquickwander_p.h index 49c49c560e..93ad8516a7 100644 --- a/src/particles/qquickwander_p.h +++ b/src/particles/qquickwander_p.h @@ -54,7 +54,6 @@ class QQuickWanderAffector : public QQuickParticleAffector Q_PROPERTY(qreal xVariance READ xVariance WRITE setXVariance NOTIFY xVarianceChanged) Q_PROPERTY(qreal yVariance READ yVariance WRITE setYVariance NOTIFY yVarianceChanged) Q_PROPERTY(AffectableParameters affectedParameter READ affectedParameter WRITE setAffectedParameter NOTIFY affectedParameterChanged) - Q_ENUMS(AffectableParameters) public: enum AffectableParameters { @@ -62,6 +61,7 @@ public: Velocity, Acceleration }; + Q_ENUM(AffectableParameters) explicit QQuickWanderAffector(QQuickItem *parent = 0); ~QQuickWanderAffector(); diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp new file mode 100644 index 0000000000..344700b8fd --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlocalclientconnection.h" +#include "qpacketprotocol.h" + +#include <QtCore/qplugin.h> +#include <QtNetwork/qlocalsocket.h> + +#include <private/qqmldebugserver_p.h> + +QT_BEGIN_NAMESPACE + +class QLocalClientConnectionPrivate { +public: + QLocalClientConnectionPrivate(); + + bool block; + QString filename; + QLocalSocket *socket; + QPacketProtocol *protocol; + QQmlDebugServer *debugServer; +}; + +QLocalClientConnectionPrivate::QLocalClientConnectionPrivate() : + block(false), + socket(0), + protocol(0), + debugServer(0) +{ +} + +QLocalClientConnection::QLocalClientConnection() : + d_ptr(new QLocalClientConnectionPrivate) +{ +} + +QLocalClientConnection::~QLocalClientConnection() +{ + if (isConnected()) + disconnect(); + delete d_ptr; +} + +void QLocalClientConnection::setServer(QQmlDebugServer *server) +{ + Q_D(QLocalClientConnection); + d->debugServer = server; +} + +bool QLocalClientConnection::isConnected() const +{ + Q_D(const QLocalClientConnection); + return d->socket && d->socket->state() == QLocalSocket::ConnectedState; +} + +void QLocalClientConnection::send(const QList<QByteArray> &messages) +{ + Q_D(QLocalClientConnection); + + if (!isConnected() || !d->protocol || !d->socket) + return; + + foreach (const QByteArray &message, messages) { + QPacket pack; + pack.writeRawData(message.data(), message.length()); + d->protocol->send(pack); + } + d->socket->flush(); +} + +void QLocalClientConnection::disconnect() +{ + Q_D(QLocalClientConnection); + + while (d->socket && d->socket->bytesToWrite() > 0) + d->socket->waitForBytesWritten(); + + // protocol might still be processing packages at this point + d->protocol->deleteLater(); + d->protocol = 0; + d->socket->deleteLater(); + d->socket = 0; +} + +bool QLocalClientConnection::waitForMessage() +{ + Q_D(QLocalClientConnection); + return d->protocol->waitForReadyRead(-1); +} + +bool QLocalClientConnection::setPortRange(int portFrom, int portTo, bool block, + const QString &hostaddress) +{ + Q_UNUSED(portFrom); + Q_UNUSED(portTo); + Q_UNUSED(block); + Q_UNUSED(hostaddress); + return false; +} + +bool QLocalClientConnection::setFileName(const QString &filename, bool block) +{ + Q_D(QLocalClientConnection); + d->filename = filename; + d->block = block; + return connect(); +} + +void QLocalClientConnection::waitForConnection() +{ + Q_D(QLocalClientConnection); + d->socket->waitForConnected(-1); +} + +bool QLocalClientConnection::connect() +{ + Q_D(QLocalClientConnection); + + d->socket = new QLocalSocket; + d->socket->setParent(this); + QObject::connect(d->socket, SIGNAL(connected()), this, SLOT(connectionEstablished())); + d->socket->connectToServer(d->filename); + qDebug("QML Debugger: Connecting to socket %s...", + d->filename.toLatin1().constData()); + return true; +} + +void QLocalClientConnection::readyRead() +{ + Q_D(QLocalClientConnection); + if (!d->protocol) + return; + + QPacket packet = d->protocol->read(); + + QByteArray content = packet.data(); + d->debugServer->receiveMessage(content); +} + +void QLocalClientConnection::connectionEstablished() +{ + Q_D(QLocalClientConnection); + + d->protocol = new QPacketProtocol(d->socket, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); + QObject::connect(d->protocol, SIGNAL(invalidPacket()), this, SLOT(invalidPacket())); + + if (d->block) + d->protocol->waitForReadyRead(-1); +} + +void QLocalClientConnection::invalidPacket() +{ + qWarning("QML Debugger: Received a corrupted packet! Giving up ..."); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractexpression.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.h index c55c86952c..424337900b 100644 --- a/src/qml/qml/qqmlabstractexpression.cpp +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.h @@ -31,63 +31,48 @@ ** ****************************************************************************/ -#include "qqmlabstractexpression_p.h" +#ifndef QLOCALCLIENTCONNECTION_H +#define QLOCALCLIENTCONNECTION_H -QT_BEGIN_NAMESPACE +#include <private/qqmldebugserverconnection_p.h> -QQmlAbstractExpression::QQmlAbstractExpression() -: m_prevExpression(0), m_nextExpression(0) -{ -} +QT_BEGIN_NAMESPACE -QQmlAbstractExpression::~QQmlAbstractExpression() +class QQmlDebugServer; +class QLocalClientConnectionPrivate; +class QLocalClientConnection : public QObject, public QQmlDebugServerConnection { - if (m_prevExpression) { - *m_prevExpression = m_nextExpression; - if (m_nextExpression) - m_nextExpression->m_prevExpression = m_prevExpression; - } - - if (m_context.isT2()) - m_context.asT2()->_s = 0; -} + Q_OBJECT + Q_DECLARE_PRIVATE(QLocalClientConnection) + Q_DISABLE_COPY(QLocalClientConnection) + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlDebugServerConnection") + Q_INTERFACES(QQmlDebugServerConnection) -QQmlContextData *QQmlAbstractExpression::context() const -{ - if (m_context.isT1()) return m_context.asT1(); - else return m_context.asT2()->_c; -} +public: + QLocalClientConnection(); + ~QLocalClientConnection(); -void QQmlAbstractExpression::setContext(QQmlContextData *context) -{ - if (m_prevExpression) { - *m_prevExpression = m_nextExpression; - if (m_nextExpression) - m_nextExpression->m_prevExpression = m_prevExpression; - m_prevExpression = 0; - m_nextExpression = 0; - } + void setServer(QQmlDebugServer *server); + bool setPortRange(int portFrom, int portTo, bool bock, const QString &hostaddress); + bool setFileName(const QString &filename, bool block); - if (m_context.isT1()) m_context = context; - else m_context.asT2()->_c = context; + bool isConnected() const; + void send(const QList<QByteArray> &messages); + void disconnect(); + bool waitForMessage(); - if (context) { - m_nextExpression = context->expressions; - if (m_nextExpression) - m_nextExpression->m_prevExpression = &m_nextExpression; - m_prevExpression = &context->expressions; - context->expressions = this; - } -} + void waitForConnection(); + bool connect(); -void QQmlAbstractExpression::refresh() -{ -} +private Q_SLOTS: + void readyRead(); + void connectionEstablished(); + void invalidPacket(); -bool QQmlAbstractExpression::isValid() const -{ - return context() != 0; -} +private: + QLocalClientConnectionPrivate *d_ptr; +}; QT_END_NAMESPACE +#endif // QLOCALCLIENTCONNECTION_H diff --git a/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pri b/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pri new file mode 100644 index 0000000000..7635523e9b --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pri @@ -0,0 +1,14 @@ +QT += core-private + +SOURCES += \ + $$PWD/qlocalclientconnection.cpp \ + $$PWD/../shared/qpacketprotocol.cpp + +HEADERS += \ + $$PWD/qlocalclientconnection.h \ + $$PWD/../shared/qpacketprotocol.h + +INCLUDEPATH += $$PWD \ + $$PWD/../shared + +OTHER_FILES += $$PWD/qlocalclientconnection.json diff --git a/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro b/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro new file mode 100644 index 0000000000..b060154933 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro @@ -0,0 +1,8 @@ +TARGET = qmldbg_local +QT = qml-private core-private + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QLocalClientConnection +load(qt_plugin) + +include(qmldbg_local.pri) diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp index e61c421bfa..9255e49364 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp @@ -211,6 +211,7 @@ void QQuickViewInspector::setSelectedItems(const QList<QQuickItem *> &items) return; QList<QObject*> objectList; + objectList.reserve(items.count()); foreach (QQuickItem *item, items) objectList << item; diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp index 2ae4edfce4..f7c0673c19 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp @@ -146,6 +146,13 @@ bool QTcpServerConnection::setPortRange(int portFrom, int portTo, bool block, return listen(); } +bool QTcpServerConnection::setFileName(const QString &fileName, bool block) +{ + Q_UNUSED(fileName); + Q_UNUSED(block); + return false; +} + void QTcpServerConnection::waitForConnection() { Q_D(QTcpServerConnection); diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h index 942fb6e12c..496d328a11 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h @@ -54,6 +54,7 @@ public: void setServer(QQmlDebugServer *server); bool setPortRange(int portFrom, int portTo, bool bock, const QString &hostaddress); + bool setFileName(const QString &fileName, bool block); bool isConnected() const; void send(const QList<QByteArray> &messages); diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 3bc48a6b33..585f80138b 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -SUBDIRS = qmldbg_tcp +SUBDIRS = qmldbg_tcp qmldbg_local qtHaveModule(quick): SUBDIRS += qmldbg_qtquick2 diff --git a/src/plugins/qmltooling/shared/abstractviewinspector.cpp b/src/plugins/qmltooling/shared/abstractviewinspector.cpp index e718cf022f..06f622a65e 100644 --- a/src/plugins/qmltooling/shared/abstractviewinspector.cpp +++ b/src/plugins/qmltooling/shared/abstractviewinspector.cpp @@ -372,6 +372,7 @@ void AbstractViewInspector::sendCurrentObjects(const QList<QObject*> &objects) ds << QByteArray(EVENT) << m_eventId++ << QByteArray(SELECT); QList<int> debugIds; + debugIds.reserve(objects.count()); foreach (QObject *object, objects) debugIds << QQmlDebugService::idForObject(object); ds << debugIds; diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 63833504f1..cc9da2817a 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -33,7 +33,7 @@ #include "qqmlirbuilder_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljslexer_p.h> diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 46b67d5983..61b538e726 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -104,11 +104,10 @@ bool QQmlTypeCompiler::compile() } if (ref->type->containsRevisionedAttributes()) { - QQmlError cacheError; ref->typePropertyCache = engine->cache(ref->type, - resolvedType->minorVersion, - cacheError); + resolvedType->minorVersion); if (!ref->typePropertyCache) { + QQmlError cacheError; cacheError.setColumn(resolvedType->location.column); cacheError.setLine(resolvedType->location.line); recordError(cacheError); @@ -696,6 +695,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob const int paramCount = s->parameters->count; QList<QByteArray> names; + names.reserve(paramCount); QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); if (paramCount) { @@ -1022,10 +1022,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio } } - QHash<QString, QStringList>::ConstIterator entry = customSignals.find(propertyName); + QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName); if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) { QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed"))); - entry = customSignals.find(alternateName); + entry = customSignals.constFind(alternateName); } if (entry == customSignals.constEnd()) { diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 9168889c8c..ea82d07e69 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -33,6 +33,7 @@ #include "qv4codegen_p.h" #include "qv4util_p.h" +#include "qv4engine_p.h" #include <QtCore/QCoreApplication> #include <QtCore/QStringList> @@ -43,7 +44,7 @@ #include <QtCore/QStack> #include <private/qqmljsast_p.h> #include <private/qv4string_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <qv4context_p.h> diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 5d954eb4fc..20db5edaa3 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -33,7 +33,7 @@ #include "qv4compileddata_p.h" #include "qv4jsir_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <private/qv4engine_p.h> #include <private/qv4function_p.h> diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 450889c275..ba4bde7a31 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -35,7 +35,7 @@ #include <qv4compileddata_p.h> #include <qv4isel_p.h> #include <private/qv4string_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QV4::Compiler::StringTableGenerator::StringTableGenerator() { @@ -44,8 +44,8 @@ QV4::Compiler::StringTableGenerator::StringTableGenerator() int QV4::Compiler::StringTableGenerator::registerString(const QString &str) { - QHash<QString, int>::ConstIterator it = stringToId.find(str); - if (it != stringToId.end()) + QHash<QString, int>::ConstIterator it = stringToId.constFind(str); + if (it != stringToId.cend()) return *it; stringToId.insert(str, strings.size()); strings.append(str); @@ -169,6 +169,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg // ### re-use existing class definitions. QList<CompiledData::JSClassMember> members; + members.reserve(count); IR::ExprList *it = args; for (int i = 0; i < count; ++i, it = it->next) { diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index eb78a0c054..59099159c1 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -447,7 +447,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backend foreach (IR::Function *irFunction, irModule->functions) compilationUnit->codeRefs[i++] = codeRefs[irFunction]; QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; - result.take(compilationUnit.take()); + result.adopt(compilationUnit.take()); return result; } @@ -1444,7 +1444,7 @@ ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &in void InstructionSelection::patchJumpAddresses() { typedef QHash<IR::BasicBlock *, QVector<ptrdiff_t> >::ConstIterator PatchIt; - for (PatchIt i = _patches.begin(), ei = _patches.end(); i != ei; ++i) { + for (PatchIt i = _patches.cbegin(), ei = _patches.cend(); i != ei; ++i) { Q_ASSERT(_addrs.contains(i.key())); ptrdiff_t target = _addrs.value(i.key()); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 54b184b4eb..46b9c784d2 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -36,7 +36,7 @@ #include "qv4jsir_p.h" #include "qv4isel_p.h" #include "qv4isel_util_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #ifndef V4_BOOTSTRAP #include <private/qqmlpropertycache_p.h> #endif diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h index 559c492dfd..58afa004a0 100644 --- a/src/qml/debugger/qqmldebug.h +++ b/src/qml/debugger/qqmldebug.h @@ -50,6 +50,7 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler QQmlDebuggingEnabler(bool printWarning = true); static bool startTcpDebugServer(int port, StartMode mode = DoNotWaitForClient, const QString &hostName = QString()); + static bool connectToLocalDebugger(const QString &socketFileName, bool block = false); }; // Execute code in constructor before first QQmlEngine is instantiated diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp index b0302181ee..0e6a182b1a 100644 --- a/src/qml/debugger/qqmldebugserver.cpp +++ b/src/qml/debugger/qqmldebugserver.cpp @@ -51,7 +51,7 @@ #include <private/qobject_p.h> #include <private/qcoreapplication_p.h> -#if defined(QT_STATIC) && ! defined(QT_NO_QML_DEBUGGER) +#if defined(QT_STATIC) && !defined(QT_NO_QML_DEBUGGER) && !defined(QT_NO_LIBRARY) #include "../../plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h" #endif @@ -94,7 +94,9 @@ const int protocolVersion = 1; int QQmlDebugServer::s_dataStreamVersion = QDataStream::Qt_4_7; // print detailed information about loading of plugins +#ifndef QT_NO_LIBRARY DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) +#endif class QQmlDebugServerThread; @@ -104,8 +106,11 @@ class QQmlDebugServerPrivate : public QObjectPrivate public: QQmlDebugServerPrivate(); - bool start(int portFrom, int portTo, bool block, const QString &hostAddress, - const QString &pluginName); + bool init(const QString &pluginName, bool block); + + template<class Action> + static bool enable(Action action); + void advertisePlugins(); void cleanup(); QQmlDebugServerConnection *loadConnectionPlugin(const QString &pluginName); @@ -136,7 +141,9 @@ public: QMutex helloMutex; QWaitCondition helloCondition; QQmlDebugServerThread *thread; +#ifndef QT_NO_LIBRARY QPluginLoader loader; +#endif QAtomicInt changeServiceStateCalls; private: @@ -164,6 +171,12 @@ public: m_hostAddress = hostAddress; } + void setFileName(const QString &fileName, bool block) + { + m_fileName = fileName; + m_block = block; + } + void run(); private: @@ -172,6 +185,7 @@ private: int m_portTo; bool m_block; QString m_hostAddress; + QString m_fileName; }; QQmlDebugServerPrivate::QQmlDebugServerPrivate() : @@ -199,7 +213,11 @@ void QQmlDebugServerPrivate::advertisePlugins() QQmlDebugStream out(&message, QIODevice::WriteOnly); QStringList pluginNames; QList<float> pluginVersions; - foreach (QQmlDebugService *service, plugins.values()) { + const QList<QQmlDebugService *> debugServices = plugins.values(); + const int count = debugServices.count(); + pluginNames.reserve(count); + pluginVersions.reserve(count); + foreach (QQmlDebugService *service, debugServices) { pluginNames << service->name(); pluginVersions << service->version(); } @@ -282,6 +300,8 @@ QQmlDebugServerConnection *QQmlDebugServerPrivate::loadConnectionPlugin( loader.unload(); } +#else + Q_UNUSED(pluginName); #endif return 0; } @@ -291,7 +311,7 @@ void QQmlDebugServerThread::run() QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance(); Q_ASSERT_X(wrapper != 0, Q_FUNC_INFO, "There should always be a debug server available here."); QQmlDebugServer *server = &wrapper->m_instance; -#if defined(QT_STATIC) && ! defined(QT_NO_QML_DEBUGGER) +#if defined(QT_STATIC) && !defined(QT_NO_QML_DEBUGGER) && !defined(QT_NO_LIBRARY) QQmlDebugServerConnection *connection = new QTcpServerConnection; #else @@ -300,10 +320,19 @@ void QQmlDebugServerThread::run() #endif if (connection) { connection->setServer(server); - if (!connection->setPortRange(m_portFrom, m_portTo, m_block, m_hostAddress)) { - delete connection; - return; + + if (m_fileName.isEmpty()) { + if (!connection->setPortRange(m_portFrom, m_portTo, m_block, m_hostAddress)) { + delete connection; + return; + } + } else { + if (!connection->setFileName(m_fileName, m_block)) { + delete connection; + return; + } } + server->d_func()->connection = connection; if (m_block) connection->waitForConnection(); @@ -367,8 +396,7 @@ static void cleanupOnShutdown() wrapper->cleanup(); } -bool QQmlDebugServerPrivate::start(int portFrom, int portTo, bool block, const QString &hostAddress, - const QString &pluginName) +bool QQmlDebugServerPrivate::init(const QString &pluginName, bool block) { if (!QQmlEnginePrivate::qml_debugging_enabled) return false; @@ -389,9 +417,7 @@ bool QQmlDebugServerPrivate::start(int portFrom, int portTo, bool block, const Q thread->setObjectName(QStringLiteral("QQmlDebugServerThread")); thread->setPluginName(pluginName); - thread->setPortRange(portFrom, portTo == -1 ? portFrom : portTo, block, hostAddress); blockingMode = block; - thread->start(); return true; } @@ -408,6 +434,7 @@ QQmlDebugServer::QQmlDebugServer() bool block = false; bool ok = false; QString hostAddress; + QString fileName; // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block] if (!appD->qmljsDebugArgumentsString().isEmpty()) { @@ -422,8 +449,8 @@ QQmlDebugServer::QQmlDebugServer() QString pluginName; QStringList lstjsDebugArguments = appD->qmljsDebugArgumentsString() .split(QLatin1Char(',')); - QStringList::const_iterator argsItEnd = lstjsDebugArguments.end(); - QStringList::const_iterator argsIt = lstjsDebugArguments.begin(); + QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend(); + QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin(); for (; argsIt != argsItEnd; ++argsIt) { const QString strArgument = *argsIt; if (strArgument.startsWith(QLatin1String("port:"))) { @@ -442,6 +469,10 @@ QQmlDebugServer::QQmlDebugServer() hostAddress = strArgument.mid(5); } else if (strArgument == QLatin1String("block")) { block = true; + } else if (strArgument.startsWith(QLatin1String("file:"))) { + pluginName = QLatin1String("qmldbg_local"); + fileName = strArgument.mid(5); + ok = !fileName.isEmpty(); } else { qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' " "detected. Ignoring the same.") @@ -451,7 +482,13 @@ QQmlDebugServer::QQmlDebugServer() if (ok) { Q_D(QQmlDebugServer); - d->start(portFrom, portTo, block, hostAddress, pluginName); + if (d->init(pluginName, block)) { + if (!fileName.isEmpty()) + d->thread->setFileName(fileName, block); + else + d->thread->setPortRange(portFrom, portTo, block, hostAddress); + d->thread->start(); + } } else { qWarning() << QString(QLatin1String( "QML Debugger: Ignoring \"-qmljsdebugger=%1\". " @@ -505,7 +542,11 @@ void QQmlDebugServer::receiveMessage(const QByteArray &message) QQmlDebugStream out(&helloAnswer, QIODevice::WriteOnly); QStringList pluginNames; QList<float> pluginVersions; - foreach (QQmlDebugService *service, d->plugins.values()) { + const QList<QQmlDebugService*> debugServices = d->plugins.values(); + const int count = debugServices.count(); + pluginNames.reserve(count); + pluginVersions.reserve(count); + foreach (QQmlDebugService *service, debugServices) { pluginNames << service->name(); pluginVersions << service->version(); } @@ -719,6 +760,7 @@ void QQmlDebugServer::sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages) { QList<QByteArray> prefixedMessages; + prefixedMessages.reserve(messages.count()); foreach (const QByteArray &message, messages) { QByteArray prefixed; QQmlDebugStream out(&prefixed, QIODevice::WriteOnly); @@ -730,7 +772,44 @@ void QQmlDebugServer::sendMessages(QQmlDebugService *service, Q_ARG(QList<QByteArray>, prefixedMessages)); } -bool QQmlDebugServer::enable(int portFrom, int portTo, bool block, const QString &hostAddress) +struct StartTcpServerAction { + int portFrom; + int portTo; + bool block; + QString hostAddress; + + StartTcpServerAction(int portFrom, int portTo, bool block, const QString &hostAddress) : + portFrom(portFrom), portTo(portTo), block(block), hostAddress(hostAddress) {} + + bool operator()(QQmlDebugServerPrivate *d) + { + if (!d->init(QLatin1String("qmldbg_tcp"), block)) + return false; + d->thread->setPortRange(portFrom, portTo == -1 ? portFrom : portTo, block, hostAddress); + d->thread->start(); + return true; + } +}; + +struct ConnectToLocalAction { + QString fileName; + bool block; + + ConnectToLocalAction(const QString &fileName, bool block) : + fileName(fileName), block(block) {} + + bool operator()(QQmlDebugServerPrivate *d) + { + if (!d->init(QLatin1String("qmldbg_local"), block)) + return false; + d->thread->setFileName(fileName, block); + d->thread->start(); + return true; + } +}; + +template<class Action> +bool QQmlDebugServerPrivate::enable(Action action) { #ifndef QT_NO_QML_DEBUGGER QQmlDebugServerInstanceWrapper *wrapper = debugServerInstance(); @@ -739,7 +818,7 @@ bool QQmlDebugServer::enable(int portFrom, int portTo, bool block, const QString QQmlDebugServerPrivate *d = wrapper->m_instance.d_func(); if (d->thread) return false; - if (!d->start(portFrom, portTo, block, hostAddress, QLatin1String("qmldbg_tcp"))) + if (!action(d)) return false; while (!wrapper->m_instance.hasConnection()) { if (!wrapper->m_instance.hasThread()) @@ -755,6 +834,57 @@ bool QQmlDebugServer::enable(int portFrom, int portTo, bool block, const QString #endif } +/*! + * \enum QQmlDebuggingEnabler::StartMode + * + * Defines the debug server's start behavior. You can interrupt QML engines starting while a debug + * client is connecting, in order to set breakpoints in or profile startup code. + * + * \value DoNotWaitForClient Run any QML engines as usual while the debug services are connecting. + * \value WaitForClient If a QML engine starts while the debug services are connecting, + * interrupt it until they are done. + */ + +/*! + * Enables debugging for QML engines created after calling this function. The debug server will + * listen on \a port at \a hostName and block the QML engine until it receives a connection if + * \a mode is \c WaitForClient. If \a mode is not specified it won't block and if \a hostName is not + * specified it will listen on all available interfaces. You can only start one debug server at a + * time. A debug server may have already been started if the -qmljsdebugger= command line argument + * was given. This method returns \c true if a new debug server was successfully started, or + * \c false otherwise. + */ +bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) +{ +#ifndef QQML_NO_DEBUG_PROTOCOL + return QQmlDebugServerPrivate::enable(StartTcpServerAction(port, port, mode == WaitForClient, hostName)); +#else + Q_UNUSED(port); + Q_UNUSED(block); + Q_UNUSED(hostName); + return false; +#endif +} + +/*! + * Enables debugging for QML engines created after calling this function. The debug server will + * connect to a debugger waiting on a local socket at the given \a socketFileName and block the QML + * engine until the connection is established if \a block is true. If \a block is not specified it + * won't block. You can only start one debug server at a time. A debug server may have already been + * started if the -qmljsdebugger= command line argument was given. This method returns \c true if a + * new debug server was successfully started, or \c false otherwise. + */ +bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName, bool block) +{ +#ifndef QQML_NO_DEBUG_PROTOCOL + return QQmlDebugServerPrivate::enable(ConnectToLocalAction(socketFileName, block)); +#else + Q_UNUSED(fileName); + Q_UNUSED(block); + return false; +#endif +} + void QQmlDebugServer::wakeEngine(QQmlEngine *engine) { // to be executed in debugger thread diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h index b2bd0b2463..f4026ca85f 100644 --- a/src/qml/debugger/qqmldebugserver_p.h +++ b/src/qml/debugger/qqmldebugserver_p.h @@ -79,7 +79,6 @@ public: void receiveMessage(const QByteArray &message); void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages); - static bool enable(int portFrom, int portTo, bool block, const QString &hostAddress); private slots: void wakeEngine(QQmlEngine *engine); diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h index 9170238b46..cfdf85a9b6 100644 --- a/src/qml/debugger/qqmldebugserverconnection_p.h +++ b/src/qml/debugger/qqmldebugserverconnection_p.h @@ -60,6 +60,7 @@ public: virtual void setServer(QQmlDebugServer *server) = 0; virtual bool setPortRange(int portFrom, int portTo, bool bock, const QString &hostaddress) = 0; + virtual bool setFileName(const QString &fileName, bool block) = 0; virtual bool isConnected() const = 0; virtual void send(const QList<QByteArray> &messages) = 0; virtual void disconnect() = 0; diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h index 9cdfc34ff1..db4f1c1152 100644 --- a/src/qml/debugger/qqmldebugservice_p.h +++ b/src/qml/debugger/qqmldebugservice_p.h @@ -62,7 +62,6 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject Q_DISABLE_COPY(QQmlDebugService) public: - explicit QQmlDebugService(const QString &, float version, QObject *parent = 0); ~QQmlDebugService(); QString name() const; @@ -88,6 +87,7 @@ public: static bool blockingMode(); protected: + explicit QQmlDebugService(const QString &, float version, QObject *parent = 0); QQmlDebugService(QQmlDebugServicePrivate &dd, const QString &name, float version, QObject *parent = 0); State registerService(); diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp index da01d00f17..0a3ddc6db5 100644 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ b/src/qml/debugger/qqmlenginedebugservice.cpp @@ -192,6 +192,7 @@ QVariant QQmlEngineDebugService::valueContents(QVariant value) const QVariantList contents; QVariantList list = value.toList(); int count = list.size(); + contents.reserve(count); for (int i = 0; i < count; i++) contents << valueContents(list.at(i)); return contents; @@ -277,13 +278,9 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, QQmlData *ddata = QQmlData::get(object); if (ddata && ddata->signalHandlers) { - QQmlAbstractBoundSignal *signalHandler = ddata->signalHandlers; + QQmlBoundSignal *signalHandler = ddata->signalHandlers; while (signalHandler) { - if (!dumpProperties) { - signalHandler = signalHandler->m_nextSignal; - continue; - } QQmlObjectProperty prop; prop.type = QQmlObjectProperty::SignalProperty; prop.hasNotifySignal = false; @@ -292,7 +289,7 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, prop.value = expr->expression(); QObject *scope = expr->scopeObject(); if (scope) { - QString methodName = QString::fromLatin1(QMetaObjectPrivate::signal(scope->metaObject(), signalHandler->index()).name()); + QString methodName = QString::fromLatin1(QMetaObjectPrivate::signal(scope->metaObject(), signalHandler->signalIndex()).name()); if (!methodName.isEmpty()) { prop.name = QLatin1String("on") + methodName[0].toUpper() + methodName.mid(1); @@ -644,11 +641,9 @@ bool QQmlEngineDebugService::setBinding(int objectId, filename, line, column); QQmlPropertyPrivate::takeSignalExpression(property, qmlExpression); } else if (property.isProperty()) { - QQmlBinding *binding = new QQmlBinding(expression.toString(), object, QQmlContextData::get(context), filename, line, column);; + QQmlBinding *binding = new QQmlBinding(expression.toString(), object, QQmlContextData::get(context), filename, line, column); binding->setTarget(property); - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, binding); - if (oldBinding) - oldBinding->destroy(); + QQmlPropertyPrivate::setBinding(binding); binding->update(); } else { ok = false; @@ -679,12 +674,7 @@ bool QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyN if (object->property(parentProperty.toLatin1()).isValid()) { QQmlProperty property(object, propertyName); - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(property); - if (oldBinding) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, 0); - if (oldBinding) - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(property); if (property.isResettable()) { // Note: this will reset the property in any case, without regard to states // Right now almost no QQuickItem has reset methods for its properties (with the @@ -762,7 +752,7 @@ bool QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex); QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(object)->handle()); QV4::Scope scope(v4); - QV4::ScopedValue v(scope, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber)); + QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber)); vmeMetaObject->setVmeMethod(prop->coreIndex, v); return true; } diff --git a/src/qml/debugger/qqmlinspectorservice.cpp b/src/qml/debugger/qqmlinspectorservice.cpp index 5a8c4487d9..0bc1257b75 100644 --- a/src/qml/debugger/qqmlinspectorservice.cpp +++ b/src/qml/debugger/qqmlinspectorservice.cpp @@ -42,8 +42,10 @@ #include <QtCore/QDir> #include <QtCore/QPluginLoader> +#ifndef QT_NO_LIBRARY // print detailed information about loading of plugins DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) +#endif QT_BEGIN_NAMESPACE @@ -140,6 +142,7 @@ void QQmlInspectorService::processMessage(const QByteArray &message) void QQmlInspectorService::loadInspectorPlugins() { +#ifndef QT_NO_LIBRARY QStringList pluginCandidates; const QStringList paths = QCoreApplication::libraryPaths(); foreach (const QString &libPath, paths) { @@ -150,12 +153,14 @@ void QQmlInspectorService::loadInspectorPlugins() } foreach (const QString &pluginPath, pluginCandidates) { - if (pluginPath.contains(QLatin1String("qmldbg_tcp"))) - continue; if (qmlDebugVerbose()) qDebug() << "QQmlInspector: Trying to load plugin " << pluginPath << "..."; QPluginLoader loader(pluginPath); + if (loader.metaData()[QLatin1String("IID")] != + QLatin1String("org.qt-project.Qt.QQmlInspectorInterface")) + continue; + if (!loader.load()) { if (qmlDebugVerbose()) qDebug() << "QQmlInspector: Error while loading: " << loader.errorString(); @@ -176,6 +181,7 @@ void QQmlInspectorService::loadInspectorPlugins() loader.unload(); } } +#endif } QT_END_NAMESPACE diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp index 32b7b38285..dade30e576 100644 --- a/src/qml/debugger/qv4debugservice.cpp +++ b/src/qml/debugger/qv4debugservice.cpp @@ -46,17 +46,10 @@ #include <QtCore/QJsonObject> #include <QtCore/QJsonValue> -const char *V4_CONNECT = "connect"; -const char *V4_DISCONNECT = "disconnect"; -const char *V4_BREAK_ON_SIGNAL = "breakonsignal"; -const char *V4_ADD_BREAKPOINT = "addBreakpoint"; -const char *V4_REMOVE_BREAKPOINT = "removeBreakpoint"; -const char *V4_PAUSE = "interrupt"; -const char *V4_ALL = "all"; -const char *V4_BREAK = "break"; - -const char *V4_FILENAME = "filename"; -const char *V4_LINENUMBER = "linenumber"; +const char *const V4_CONNECT = "connect"; +const char *const V4_DISCONNECT = "disconnect"; +const char *const V4_BREAK_ON_SIGNAL = "breakonsignal"; +const char *const V4_PAUSE = "interrupt"; #define NO_PROTOCOL_TRACING #ifdef NO_PROTOCOL_TRACING @@ -230,7 +223,7 @@ protected: virtual void addObject(const QString &name, const QV4::Value &value) { QV4::Scope scope(engine()); - QV4::ScopedObject obj(scope, value.asObject()); + QV4::ScopedObject obj(scope, value.as<QV4::Object>()); int ref = cachedObjectRef(obj); if (ref != -1) { @@ -356,7 +349,7 @@ class QV4DebugServicePrivate : public QQmlConfigurableDebugServicePrivate public: QV4DebugServicePrivate(); - ~QV4DebugServicePrivate() { qDeleteAll(handlers.values()); } + ~QV4DebugServicePrivate() { qDeleteAll(handlers); } static QByteArray packMessage(const QByteArray &command, const QByteArray &message = QByteArray()) { diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 09e5b14c97..b5765b5705 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -241,16 +241,16 @@ void Assembler::enterStandardStackFrame(const RegisterInformation ®ularRegist subPtr(TrustedImm32(frameSize), StackPointerRegister); Address slotAddr(StackFrameRegister, 0); - for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) { - Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister()); - slotAddr.offset -= RegisterSize; - storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr); - } for (int i = 0, ei = fpRegistersToSave.size(); i < ei; ++i) { Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint()); slotAddr.offset -= sizeof(double); JSC::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr); } + for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) { + Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister()); + slotAddr.offset -= RegisterSize; + storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr); + } } void Assembler::leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave, @@ -259,16 +259,16 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation ®ularRegist Address slotAddr(StackFrameRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double)); // restore the callee saved registers - for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) { - Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint()); - JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>()); - slotAddr.offset += sizeof(double); - } for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) { Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister()); loadPtr(slotAddr, regularRegistersToSave.at(i).reg<RegisterID>()); slotAddr.offset += RegisterSize; } + for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) { + Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint()); + JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>()); + slotAddr.offset += sizeof(double); + } Q_ASSERT(slotAddr.offset == 0); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 3b65acb26c..f4b44ce882 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -565,6 +565,8 @@ public: moveIntsToDouble(JSC::ARMRegisters::r0, JSC::ARMRegisters::r1, dest, FPGpr0); #elif defined(Q_PROCESSOR_X86) moveIntsToDouble(JSC::X86Registers::eax, JSC::X86Registers::edx, dest, FPGpr0); +#elif defined(Q_PROCESSOR_MIPS) + moveIntsToDouble(JSC::MIPSRegisters::v0, JSC::MIPSRegisters::v1, dest, FPGpr0); #else subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister); Pointer tmp(StackPointerRegister, 0); @@ -595,6 +597,14 @@ public: destination.offset += 4; store32(JSC::ARMRegisters::r1, destination); } +#elif defined(Q_PROCESSOR_MIPS) + void storeReturnValue(const Pointer &dest) + { + Pointer destination = dest; + store32(JSC::MIPSRegisters::v0, destination); + destination.offset += 4; + store32(JSC::MIPSRegisters::v1, destination); + } #endif void storeReturnValue(IR::Expr *target) @@ -820,6 +830,8 @@ public: else #if OS(WINDOWS) && CPU(X86_64) loadArgumentOnStack<argumentNumber>(value, argumentNumber); +#elif CPU(MIPS) // Stack space for 4 arguments needs to be allocated for MIPS platforms. + loadArgumentOnStack<argumentNumber>(value, argumentNumber + 4); #else // Sanity: loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value, argumentNumber); #endif diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index c6c8023cd7..8b051fcb3d 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -352,7 +352,9 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta } } - if (op == IR::OpSub) { + // Special cases: + switch (op) { + case IR::OpSub: if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister && targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister @@ -368,11 +370,27 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta } as->storeInt32(targetReg, target); return true; + + case IR::OpLShift: + case IR::OpRShift: + case IR::OpURShift: + if (IR::Const *c = rightSource->asConst()) { + if ((QV4::Primitive::toUInt32(c->value) & 0x1f) == 0) { + Assembler::RegisterID r = as->toInt32Register(leftSource, targetReg); + as->storeInt32(r, target); + return true; + } + } + break; + + default: + break; } Assembler::RegisterID l = as->toInt32Register(leftSource, targetReg); if (IR::Const *c = rightSource->asConst()) { // All cases of Y = X op Const Assembler::TrustedImm32 r(int(c->value)); + Assembler::TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f); switch (op) { case IR::OpBitAnd: as->and32(r, l, targetReg); break; @@ -381,9 +399,9 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpAdd: as->add32(r, l, targetReg); break; case IR::OpMul: as->mul32(r, l, targetReg); break; - case IR::OpLShift: r.m_value &= 0x1f; as->lshift32(l, r, targetReg); break; - case IR::OpRShift: r.m_value &= 0x1f; as->rshift32(l, r, targetReg); break; - case IR::OpURShift: r.m_value &= 0x1f; as->urshift32(l, r, targetReg); + case IR::OpLShift: as->lshift32(l, ur, targetReg); break; + case IR::OpRShift: as->rshift32(l, ur, targetReg); break; + case IR::OpURShift: as->urshift32(l, ur, targetReg); as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! return true; @@ -415,32 +433,33 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpAdd: as->add32(l, r, targetReg); break; case IR::OpMul: as->mul32(l, r, targetReg); break; -#if CPU(ARM) || CPU(X86) || CPU(X86_64) - // The ARM assembler will generate an and with 0x1f for us, and Intel will do it on the CPU. - +#if CPU(X86) || CPU(X86_64) + // Intel does the & 0x1f on the CPU, so: case IR::OpLShift: as->lshift32(l, r, targetReg); break; case IR::OpRShift: as->rshift32(l, r, targetReg); break; case IR::OpURShift: as->urshift32(l, r, targetReg); as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! return true; #else - case IR::OpLShift: - as->move(r, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - as->lshift32(l, Assembler::ScratchRegister, targetReg); - break; - - case IR::OpRShift: - as->move(r, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - as->rshift32(l, Assembler::ScratchRegister, targetReg); - break; - + // Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do + // surprising stuff when shifting over 0 bits. +#define CHECK_RHS(op) { \ + as->and32(Assembler::TrustedImm32(0x1f), r, Assembler::ScratchRegister); \ + Assembler::Jump notZero = as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); \ + as->move(l, targetReg); \ + Assembler::Jump done = as->jump(); \ + notZero.link(as); \ + op; \ + done.link(as); \ +} + case IR::OpLShift: CHECK_RHS(as->lshift32(l, Assembler::ScratchRegister, targetReg)); break; + case IR::OpRShift: CHECK_RHS(as->rshift32(l, Assembler::ScratchRegister, targetReg)); break; case IR::OpURShift: - as->move(r, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! + CHECK_RHS(as->urshift32(l, Assembler::ScratchRegister, targetReg)); + as->storeUInt32(targetReg, target); + // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations! return true; +#undef CHECK_RHS #endif case IR::OpSub: // already handled before diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index da511cd1eb..09e295e4f0 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -317,7 +317,7 @@ const void *InstructionSelection::addConstantTable(QVector<Primitive> *values) QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep() { QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; - result.take(compilationUnit.take()); + result.adopt(compilationUnit.take()); return result; } @@ -1383,11 +1383,14 @@ void InstructionSelection::visitRet(IR::Ret *s) // this only happens if the method doesn't have a return statement and can // only exit through an exception } else if (IR::Temp *t = s->expr->asTemp()) { -#if CPU(X86) || CPU(ARM) +#if CPU(X86) || CPU(ARM) || CPU(MIPS) # if CPU(X86) Assembler::RegisterID lowReg = JSC::X86Registers::eax; Assembler::RegisterID highReg = JSC::X86Registers::edx; +# elif CPU(MIPS) + Assembler::RegisterID lowReg = JSC::MIPSRegisters::v0; + Assembler::RegisterID highReg = JSC::MIPSRegisters::v1; # else // CPU(ARM) Assembler::RegisterID lowReg = JSC::ARMRegisters::r0; Assembler::RegisterID highReg = JSC::ARMRegisters::r1; @@ -1477,6 +1480,9 @@ void InstructionSelection::visitRet(IR::Ret *s) #elif CPU(ARM) _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::ARMRegisters::r0); _as->move(Assembler::TrustedImm32(retVal.tag), JSC::ARMRegisters::r1); +#elif CPU(MIPS) + _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::MIPSRegisters::v0); + _as->move(Assembler::TrustedImm32(retVal.tag), JSC::MIPSRegisters::v1); #else _as->move(Assembler::TrustedImm64(retVal.val), Assembler::ReturnValueRegister); #endif @@ -1504,6 +1510,9 @@ void InstructionSelection::visitRet(IR::Ret *s) #elif CPU(ARM) _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::ARMRegisters::r0); _as->move(Assembler::TrustedImm32(retVal.tag), JSC::ARMRegisters::r1); +#elif CPU(MIPS) + _as->move(Assembler::TrustedImm32(retVal.int_32), JSC::MIPSRegisters::v0); + _as->move(Assembler::TrustedImm32(retVal.tag), JSC::MIPSRegisters::v1); #else _as->move(Assembler::TrustedImm64(retVal.val), Assembler::ReturnValueRegister); #endif diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index ae06a99d2a..48b7badd56 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -35,7 +35,7 @@ #include <QtCore/QDebug> #include "qv4regalloc_p.h" #include "qv4alloca_p.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <algorithm> #if defined(Q_CC_MINGW) diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 05741f0ae5..76c768e4f9 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -346,6 +346,71 @@ public: static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::ARMRegisters::lr); } #endif // Linux on ARM (32 bit) +#if defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) + enum { RegAllocIsSupported = 1 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::MIPSRegisters::fp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::MIPSRegisters::sp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::MIPSRegisters::s0; + static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::MIPSRegisters::s1; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::MIPSRegisters::s2; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + // Note: t0, t1, t2, t3 and f16 are already used by MacroAssemblerMIPS. + << RI(JSC::MIPSRegisters::t4, QStringLiteral("t4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t5, QStringLiteral("t5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t6, QStringLiteral("t6"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t7, QStringLiteral("t7"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::t8, QStringLiteral("t8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::s0, QStringLiteral("s0"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::MIPSRegisters::s1, QStringLiteral("s1"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::MIPSRegisters::s2, QStringLiteral("s2"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::MIPSRegisters::s3, QStringLiteral("s3"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f4, QStringLiteral("f4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f6, QStringLiteral("f6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f8, QStringLiteral("f8"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f10, QStringLiteral("f10"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f18, QStringLiteral("f18"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f20, QStringLiteral("f20"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f22, QStringLiteral("f22"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f24, QStringLiteral("f24"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f26, QStringLiteral("f26"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::MIPSRegisters::f28, QStringLiteral("f28"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc) + ; + } + +#undef HAVE_ALU_OPS_WITH_MEM_OPERAND +#undef VALUE_FITS_IN_REGISTER + static const int RegisterSize = 4; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 4; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::MIPSRegisters::a0, + JSC::MIPSRegisters::a1, + JSC::MIPSRegisters::a2, + JSC::MIPSRegisters::a3 + }; + + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 8; + static const int StackShadowSpace = 4 * RegisterSize; // Stack space for 4 argument registers. + static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(JSC::MIPSRegisters::ra); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::MIPSRegisters::ra); } +#endif // Linux on MIPS (32 bit) + public: // utility functions static RegisterInformation getRegisterInfo() { diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index ee27c21aed..d9615d496f 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -77,7 +77,6 @@ Q_DECLARE_METATYPE(QList<int>) \ingroup qtjavascript \inmodule QtQml - \mainclass \section1 Evaluating Scripts @@ -271,7 +270,7 @@ void QJSEngine::installTranslatorFunctions(const QJSValue &object) if (val) obj = val; if (!obj) - obj = scope.engine->globalObject(); + obj = scope.engine->globalObject; #ifndef QT_NO_TRANSLATION obj->defineDefaultProperty(QStringLiteral("qsTranslate"), QV4::GlobalExtensions::method_qsTranslate); obj->defineDefaultProperty(QStringLiteral("QT_TRANSLATE_NOOP"), QV4::GlobalExtensions::method_qsTranslateNoOp); @@ -281,7 +280,7 @@ void QJSEngine::installTranslatorFunctions(const QJSValue &object) obj->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp); // string prototype extension - scope.engine->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("arg"), + scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), QV4::GlobalExtensions::method_string_arg); #endif } @@ -319,7 +318,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in QV4::ExecutionEngine *v4 = d->m_v4Engine; QV4::Scope scope(v4); QV4::ScopedContext ctx(scope, v4->currentContext()); - if (ctx->d() != v4->rootContext()) + if (ctx->d() != v4->rootContext()->d()) ctx = v4->pushGlobalContext(); QV4::ScopedValue result(scope); @@ -331,7 +330,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in result = script.run(); if (scope.engine->hasException) result = v4->catchException(); - if (ctx->d() != v4->rootContext()) + if (ctx->d() != v4->rootContext()->d()) v4->popContext(); return QJSValue(v4, result->asReturnedValue()); } @@ -414,7 +413,7 @@ QJSValue QJSEngine::globalObject() const { Q_D(const QJSEngine); QV4::Scope scope(d->m_v4Engine); - QV4::ScopedValue v(scope, d->m_v4Engine->globalObject()); + QV4::ScopedValue v(scope, d->m_v4Engine->globalObject); return QJSValue(d->m_v4Engine, v->asReturnedValue()); } diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 50669c46a8..6d0c7cfdda 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -37,13 +37,14 @@ #include "qjsengine.h" #include "qjsvalue.h" #include "qjsvalue_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4object_p.h" #include "qv4functionobject_p.h" #include "qv4dateobject_p.h" #include "qv4runtime_p.h" #include "qv4variantobject_p.h" #include "qv4regexpobject_p.h" +#include "qv4errorobject_p.h" #include "private/qv8engine_p.h" #include <private/qv4mm_p.h> #include <private/qv4scopedvalue_p.h> @@ -57,7 +58,6 @@ \ingroup qtjavascript \inmodule QtQml - \mainclass QJSValue supports the types defined in the \l{ECMA-262} standard: The primitive types, which are Undefined, Null, Boolean, @@ -317,8 +317,7 @@ bool QJSValue::isError() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - Object *o = val->asObject(); - return o && o->asErrorObject(); + return val->as<ErrorObject>(); } /*! @@ -332,7 +331,7 @@ bool QJSValue::isArray() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - return val->asArrayObject(); + return val->as<ArrayObject>(); } /*! @@ -349,7 +348,7 @@ bool QJSValue::isObject() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - return val->asObject(); + return val->as<Object>(); } /*! @@ -363,7 +362,7 @@ bool QJSValue::isCallable() const QV4::Value *val = QJSValuePrivate::getValue(this); if (!val) return false; - return val->asFunctionObject(); + return val->as<FunctionObject>(); } /*! @@ -589,7 +588,7 @@ QVariant QJSValue::toVariant() const QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch); Q_ASSERT(val); - if (Object *o = val->asObject()) + if (Object *o = val->as<Object>()) return o->engine()->toVariant(*val, /*typeHint*/ -1, /*createJSValueForObjects*/ false); if (val->isString()) @@ -628,7 +627,7 @@ QJSValue QJSValue::call(const QJSValueList &args) if (!val) return QJSValue(); - FunctionObject *f = val->asFunctionObject(); + FunctionObject *f = val->as<FunctionObject>(); if (!f) return QJSValue(); @@ -637,7 +636,7 @@ QJSValue QJSValue::call(const QJSValueList &args) Scope scope(engine); ScopedCallData callData(scope, args.length()); - callData->thisObject = engine->globalObject()->asReturnedValue(); + callData->thisObject = engine->globalObject; for (int i = 0; i < args.size(); ++i) { if (!QJSValuePrivate::checkEngine(engine, args.at(i))) { qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); @@ -679,7 +678,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList if (!val) return QJSValue(); - FunctionObject *f = val->asFunctionObject(); + FunctionObject *f = val->as<FunctionObject>(); if (!f) return QJSValue(); @@ -733,7 +732,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) if (!val) return QJSValue(); - FunctionObject *f = val->asFunctionObject(); + FunctionObject *f = val->as<FunctionObject>(); if (!f) return QJSValue(); @@ -789,7 +788,7 @@ QJSValue QJSValue::prototype() const if (!engine) return QJSValue(); QV4::Scope scope(engine); - ScopedObject o(scope, QJSValuePrivate::getValue(this)->asObject()); + ScopedObject o(scope, QJSValuePrivate::getValue(this)->as<Object>()); if (!o) return QJSValue(); ScopedObject p(scope, o->prototype()); @@ -1029,7 +1028,7 @@ QJSValue QJSValue::property(quint32 arrayIndex) const if (!o) return QJSValue(); - QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex)); + QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax()) : o->getIndexed(arrayIndex)); if (engine->hasException) engine->catchException(); return QJSValue(engine, result->asReturnedValue()); @@ -1108,7 +1107,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) if (arrayIndex != UINT_MAX) o->putIndexed(arrayIndex, v); else - o->put(engine->id_uintMax, v); + o->put(engine->id_uintMax(), v); if (engine->hasException) engine->catchException(); } @@ -1224,7 +1223,7 @@ QDateTime QJSValue::toDateTime() const { QV4::Value *val = QJSValuePrivate::getValue(this); if (val) { - QV4::DateObject *date = val->asDateObject(); + QV4::DateObject *date = val->as<DateObject>(); if (date) return date->toQDateTime(); } @@ -1238,7 +1237,7 @@ QDateTime QJSValue::toDateTime() const bool QJSValue::isDate() const { QV4::Value *val = QJSValuePrivate::getValue(this); - return val && val->asDateObject(); + return val && val->as<DateObject>(); } /*! diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h index 93a28a4a5f..08dc184412 100644 --- a/src/qml/jsapi/qjsvalue_p.h +++ b/src/qml/jsapi/qjsvalue_p.h @@ -47,7 +47,7 @@ #include <qjsvalue.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4string_p.h> #include <private/qv4engine_p.h> #include <private/qv4object_p.h> diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index 1ee4121f5c..a24953ae3f 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -52,9 +52,6 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) QV4::Scope scope(e); QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&v)); iterator.set(e, e->newForEachIteratorObject(o)); - - currentName = (QV4::String *)0; - nextName = (QV4::String *)0; } @@ -102,8 +99,10 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object) QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; QV4::ScopedString nm(scope); - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); - d_ptr->nextName = nm; + QV4::Property nextProperty; + QV4::PropertyAttributes nextAttributes; + it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + d_ptr->nextName.set(v4, nm.asReturnedValue()); } /*! @@ -125,7 +124,7 @@ bool QJSValueIterator::hasNext() const QV4::Value *val = QJSValuePrivate::getValue(&d_ptr->value); if (!val || !val->isObject()) return false; - return !!d_ptr->nextName || d_ptr->nextIndex != UINT_MAX; + return d_ptr->nextName.as<QV4::String>() || d_ptr->nextIndex != UINT_MAX; } /*! @@ -143,8 +142,6 @@ bool QJSValueIterator::next() return false; d_ptr->currentName = d_ptr->nextName; d_ptr->currentIndex = d_ptr->nextIndex; - d_ptr->currentProperty.copy(&d_ptr->nextProperty, d_ptr->nextAttributes); - d_ptr->currentAttributes = d_ptr->nextAttributes; QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); if (!v4) @@ -152,9 +149,11 @@ bool QJSValueIterator::next() QV4::Scope scope(v4); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); QV4::ScopedString nm(scope); - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); - d_ptr->nextName = nm; - return !!d_ptr->currentName || d_ptr->currentIndex != UINT_MAX; + QV4::Property nextProperty; + QV4::PropertyAttributes nextAttributes; + it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + d_ptr->nextName.set(v4, nm.asReturnedValue()); + return d_ptr->currentName.as<QV4::String>() || d_ptr->currentIndex != UINT_MAX; } /*! @@ -168,8 +167,8 @@ QString QJSValueIterator::name() const QV4::Value *val = QJSValuePrivate::getValue(&d_ptr->value); if (!val || !val->isObject()) return QString(); - if (!!d_ptr->currentName) - return d_ptr->currentName->toQString(); + if (QV4::String *s = d_ptr->currentName.as<QV4::String>()) + return s->toQString(); if (d_ptr->currentIndex < UINT_MAX) return QString::number(d_ptr->currentIndex); return QString(); @@ -192,10 +191,10 @@ QJSValue QJSValueIterator::value() const if (!obj) return QJSValue(); - if (!d_ptr->currentName && d_ptr->currentIndex == UINT_MAX) + if (!d_ptr->currentName.as<QV4::String>() && d_ptr->currentIndex == UINT_MAX) return QJSValue(); - QV4::ScopedValue v(scope, obj->getValue(*obj, &d_ptr->currentProperty, d_ptr->currentAttributes)); + QV4::ScopedValue v(scope, d_ptr->currentIndex == UINT_MAX ? obj->get(d_ptr->currentName.as<QV4::String>()) : obj->getIndexed(d_ptr->currentIndex)); if (scope.hasException()) { engine->catchException(); return QJSValue(); @@ -214,8 +213,8 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) d_ptr->value = object; d_ptr->currentIndex = UINT_MAX; d_ptr->nextIndex = UINT_MAX; - d_ptr->currentName = (QV4::String *)0; - d_ptr->nextName = (QV4::String *)0; + d_ptr->currentName.clear(); + d_ptr->nextName.clear(); QV4::ExecutionEngine *v4 = d_ptr->iterator.engine(); if (!v4) { d_ptr->iterator.clear(); @@ -228,8 +227,10 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; QV4::ScopedString nm(scope); - it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); - d_ptr->nextName = nm; + QV4::Property nextProperty; + QV4::PropertyAttributes nextAttributes; + it->d()->it.next(nm.getRef(), &d_ptr->nextIndex, &nextProperty, &nextAttributes); + d_ptr->nextName.set(v4, nm.asReturnedValue()); return *this; } diff --git a/src/qml/jsapi/qjsvalueiterator_p.h b/src/qml/jsapi/qjsvalueiterator_p.h index c17fedf73e..b0d0b2efda 100644 --- a/src/qml/jsapi/qjsvalueiterator_p.h +++ b/src/qml/jsapi/qjsvalueiterator_p.h @@ -48,15 +48,9 @@ public: QJSValue value; QV4::PersistentValue iterator; - // ### GC - QV4::Property currentProperty; - QV4::PropertyAttributes currentAttributes; - QV4::StringValue currentName; + QV4::PersistentValue currentName; uint currentIndex; - // ### GC - QV4::Property nextProperty; - QV4::PropertyAttributes nextAttributes; - QV4::StringValue nextName; + QV4::PersistentValue nextName; uint nextIndex; }; diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ef44ca6f4d..5ffdebe328 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -10,7 +10,6 @@ SOURCES += \ $$PWD/qv4lookup.cpp \ $$PWD/qv4identifier.cpp \ $$PWD/qv4identifiertable.cpp \ - $$PWD/qv4mm.cpp \ $$PWD/qv4managed.cpp \ $$PWD/qv4internalclass.cpp \ $$PWD/qv4sparsearray.cpp \ @@ -40,7 +39,6 @@ SOURCES += \ $$PWD/qv4sequenceobject.cpp \ $$PWD/qv4include.cpp \ $$PWD/qv4qobjectwrapper.cpp \ - $$PWD/qv4qmlextensions.cpp \ $$PWD/qv4vme_moth.cpp \ $$PWD/qv4profiling.cpp \ $$PWD/qv4arraybuffer.cpp \ @@ -57,7 +55,6 @@ HEADERS += \ $$PWD/qv4lookup_p.h \ $$PWD/qv4identifier_p.h \ $$PWD/qv4identifiertable_p.h \ - $$PWD/qv4mm_p.h \ $$PWD/qv4managed_p.h \ $$PWD/qv4internalclass_p.h \ $$PWD/qv4sparsearray_p.h \ @@ -90,7 +87,6 @@ HEADERS += \ $$PWD/qv4sequenceobject_p.h \ $$PWD/qv4include_p.h \ $$PWD/qv4qobjectwrapper_p.h \ - $$PWD/qv4qmlextensions_p.h \ $$PWD/qv4vme_moth_p.h \ $$PWD/qv4profiling_p.h \ $$PWD/qv4arraybuffer_p.h \ @@ -102,7 +98,7 @@ HEADERS += \ HEADERS += \ $$PWD/qv4runtime_p.h \ - $$PWD/qv4value_inl_p.h \ + $$PWD/qv4value_p.h \ $$PWD/qv4string_p.h \ $$PWD/qv4value_p.h diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 92c77570af..55753aec24 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -33,6 +33,7 @@ #include <qv4argumentsobject_p.h> #include <qv4alloca_p.h> #include <qv4scopedvalue_p.h> +#include "qv4string_p.h" using namespace QV4; @@ -40,7 +41,7 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject); Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) : Heap::Object(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass, - context->d()->engine->objectPrototype.asObject()) + context->d()->engine->objectPrototype()) , context(context->d()) , fullyCreated(false) { @@ -53,21 +54,21 @@ Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context) args->setArrayType(Heap::ArrayData::Complex); if (context->d()->strictMode) { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee)); - Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller)); - args->propertyAt(CalleePropertyIndex)->value = v4->thrower; - args->propertyAt(CalleePropertyIndex)->set = v4->thrower; - args->propertyAt(CallerPropertyIndex)->value = v4->thrower; - args->propertyAt(CallerPropertyIndex)->set = v4->thrower; + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); + Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); + args->propertyAt(CalleePropertyIndex)->value = v4->thrower(); + args->propertyAt(CalleePropertyIndex)->set = v4->thrower(); + args->propertyAt(CallerPropertyIndex)->value = v4->thrower(); + args->propertyAt(CallerPropertyIndex)->set = v4->thrower(); args->arrayReserve(context->argc()); args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee)); + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); args->memberData()->data[CalleePropertyIndex] = context->d()->function->asReturnedValue(); } - Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length)); + Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); args->memberData()->data[LengthPropertyIndex] = Primitive::fromInt32(context->d()->callData->argc); } @@ -144,9 +145,9 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con return result; } -ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *hasProperty) { - ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); if (args->fullyCreated()) return Object::getIndexed(m, index, hasProperty); @@ -199,11 +200,11 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction); -ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) +ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArgumentsGetterFunction *>(getter)->engine(); + ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine(); Scope scope(v4); - Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter)); + Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) return v4->throwTypeError(); @@ -214,11 +215,11 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction); -ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) +ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArgumentsSetterFunction *>(setter)->engine(); + ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine(); Scope scope(v4); - Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter)); + Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) return v4->throwTypeError(); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 43cd6d1dee..19659429a7 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -59,9 +59,9 @@ struct ArgumentsObject : Object { CallerPropertyIndex = 3 }; ArgumentsObject(QV4::CallContext *context); - CallContext *context; + Pointer<CallContext> context; bool fullyCreated; - MemberData *mappedArguments; + Pointer<MemberData> mappedArguments; }; } @@ -71,7 +71,7 @@ struct ArgumentsGetterFunction: FunctionObject V4_OBJECT2(ArgumentsGetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(Managed *that, CallData *d); + static ReturnedValue call(const Managed *that, CallData *d); }; inline @@ -86,7 +86,7 @@ struct ArgumentsSetterFunction: FunctionObject V4_OBJECT2(ArgumentsSetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; inline @@ -111,7 +111,7 @@ struct ArgumentsObject: Object { } bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void putIndexed(Managed *m, uint index, const Value &value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index 11664f1194..3106d3af23 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -33,6 +33,7 @@ #include "qv4arraybuffer_p.h" #include "qv4typedarray_p.h" #include "qv4dataview_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -44,9 +45,9 @@ Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) +ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); ScopedValue l(scope, callData->argument(0)); @@ -64,7 +65,7 @@ ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) } -ReturnedValue ArrayBufferCtor::call(Managed *that, CallData *callData) +ReturnedValue ArrayBufferCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -83,7 +84,7 @@ ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype.asObject()) + : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) { data = QTypedArrayData<char>::allocate(length + 1); if (!data) { @@ -96,7 +97,7 @@ Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, size_t length) } Heap::ArrayBuffer::ArrayBuffer(ExecutionEngine *e, const QByteArray& array) - : Heap::Object(e->emptyClass, e->arrayBufferPrototype.asObject()) + : Heap::Object(e->emptyClass, e->arrayBufferPrototype()) , data(const_cast<QByteArray&>(array).data_ptr()) { data->ref.ref(); @@ -138,10 +139,10 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); } @@ -172,7 +173,7 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size); double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size); - ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor)); + ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index fe3150618d..a7f9e92c80 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -61,8 +61,8 @@ struct ArrayBufferCtor: FunctionObject { V4_OBJECT2(ArrayBufferCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static ReturnedValue method_isView(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index afcfa00905..627aed0192 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -33,13 +33,14 @@ #include "qv4arraydata_p.h" #include "qv4object_p.h" #include "qv4functionobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4runtime_p.h" #include "qv4argumentsobject_p.h" +#include "qv4string_p.h" using namespace QV4; -const QV4::ManagedVTable QV4::ArrayData::static_vtbl = { +const QV4::VTable QV4::ArrayData::static_vtbl = { 0, QV4::ArrayData::IsExecutionContext, QV4::ArrayData::IsString, @@ -230,7 +231,7 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) bool SimpleArrayData::put(Object *o, uint index, const Value &value) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor()); // ### honour attributes dd->data(index) = value; @@ -244,7 +245,7 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value) bool SimpleArrayData::del(Object *o, uint index) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index >= dd->len) return true; @@ -266,12 +267,12 @@ void SimpleArrayData::setAttribute(Object *o, uint index, PropertyAttributes att void SimpleArrayData::push_front(Object *o, const Value *values, uint n) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); if (dd->len + n > dd->alloc) { realloc(o, Heap::ArrayData::Simple, dd->len + n, false); Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); - dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } dd->offset = (dd->offset - n) % dd->alloc; dd->len += n; @@ -281,7 +282,7 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) ReturnedValue SimpleArrayData::pop_front(Object *o) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); if (!dd->len) return Encode::undefined(); @@ -294,7 +295,7 @@ ReturnedValue SimpleArrayData::pop_front(Object *o) uint SimpleArrayData::truncate(Object *o, uint newLen) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (dd->len < newLen) return newLen; @@ -318,10 +319,10 @@ uint SimpleArrayData::length(const Heap::ArrayData *d) bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n) { - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index + n > dd->alloc) { reallocate(o, index + n + 1, false); - dd = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } for (uint i = dd->len; i < index; ++i) dd->data(i) = Primitive::emptyValue(); @@ -369,13 +370,13 @@ Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttr uint SparseArrayData::allocate(Object *o, bool doubleSlot) { Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Sparse); - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (doubleSlot) { uint *last = &dd->freeList; while (1) { if (*last == UINT_MAX) { reallocate(o, dd->alloc + 2, true); - dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); last = &dd->freeList; Q_ASSERT(*last != UINT_MAX); } @@ -393,7 +394,7 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) } else { if (dd->freeList == UINT_MAX) { reallocate(o, dd->alloc + 1, false); - dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } uint idx = dd->freeList; Q_ASSERT(idx != UINT_MAX); @@ -418,12 +419,12 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) if (value.isEmpty()) return true; - Heap::SparseArrayData *s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *s = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = s->sparse->insert(index); Q_ASSERT(n->value == UINT_MAX || !s->attrs || !s->attrs[n->value].isAccessor()); if (n->value == UINT_MAX) n->value = allocate(o); - s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + s = o->d()->arrayData.cast<Heap::SparseArrayData>(); s->arrayData[n->value] = value; if (s->attrs) s->attrs[n->value] = Attr_Data; @@ -432,7 +433,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) bool SparseArrayData::del(Object *o, uint index) { - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *dd = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = dd->sparse->findNode(index); if (!n) @@ -468,28 +469,28 @@ bool SparseArrayData::del(Object *o, uint index) void SparseArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = d->sparse->insert(index); if (n->value == UINT_MAX) { n->value = allocate(o, attrs.isAccessor()); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); } else if (attrs.isAccessor() != d->attrs[n->value].isAccessor()) { // need to convert the slot free(o->arrayData(), n->value); n->value = allocate(o, attrs.isAccessor()); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); } d->attrs[n->value] = attrs; } void SparseArrayData::push_front(Object *o, const Value *values, uint n) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); for (int i = n - 1; i >= 0; --i) { uint idx = allocate(o); - d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SparseArrayData>(); d->arrayData[idx] = values[i]; d->sparse->push_front(idx); } @@ -497,7 +498,7 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n) ReturnedValue SparseArrayData::pop_front(Object *o) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); uint idx = d->sparse->pop_front(); ReturnedValue v; @@ -512,7 +513,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o) uint SparseArrayData::truncate(Object *o, uint newLen) { - Heap::SparseArrayData *d = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *begin = d->sparse->lowerBound(newLen); if (begin != d->sparse->end()) { SparseArrayNode *it = d->sparse->end()->previousNode(); @@ -606,11 +607,11 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) Property *ArrayData::insert(Object *o, uint index, bool isAccessor) { if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) { - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (index < 0x1000 || index < d->len + (d->len >> 2)) { if (index >= d->alloc) { o->arrayReserve(index + 1); - d = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } if (index >= d->len) { // mark possible hole in the array @@ -623,11 +624,11 @@ Property *ArrayData::insert(Object *o, uint index, bool isAccessor) } o->initSparseArray(); - Heap::SparseArrayData *s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *s = o->d()->arrayData.cast<Heap::SparseArrayData>(); SparseArrayNode *n = s->sparse->insert(index); if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); - s = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + s = o->d()->arrayData.cast<Heap::SparseArrayData>(); return reinterpret_cast<Property *>(s->arrayData + n->value); } @@ -737,7 +738,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c if (!arrayData || !arrayData->length()) return; - if (!(comparefn.isUndefined() || comparefn.asObject())) { + if (!(comparefn.isUndefined() || comparefn.as<Object>())) { engine->throwTypeError(); return; } @@ -755,7 +756,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c thisObject->setArrayData(0); ArrayData::realloc(thisObject, Heap::ArrayData::Simple, sparse->sparse()->nEntries(), sparse->attrs() ? true : false); - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(thisObject->d()->arrayData); + Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); SparseArrayNode *n = sparse->sparse()->begin(); uint i = 0; @@ -795,7 +796,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c } } else { - Heap::SimpleArrayData *d = static_cast<Heap::SimpleArrayData *>(thisObject->d()->arrayData); + Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); if (len > d->len) len = d->len; diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 915e862bbb..667827d1e9 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -47,7 +47,7 @@ namespace QV4 { Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ static const QV4::ArrayVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ const Data *d() const { return static_cast<const Data *>(m); } \ Data *d() { return static_cast<Data *>(m); } @@ -57,7 +57,7 @@ struct ArrayData; struct ArrayVTable { - ManagedVTable managedVTable; + VTable vTable; uint type; Heap::ArrayData *(*reallocate)(Object *o, uint n, bool enforceAttributes); ReturnedValue (*get)(const Heap::ArrayData *d, uint index); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 231eb93dd5..25d3d9329b 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -37,6 +37,7 @@ #include "qv4scopedvalue_p.h" #include "qv4argumentsobject_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -47,9 +48,9 @@ Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) +ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<ArrayCtor *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine(); Scope scope(v4); ScopedArrayObject a(scope, v4->newArrayObject()); uint len; @@ -72,7 +73,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) return a.asReturnedValue(); } -ReturnedValue ArrayCtor::call(Managed *that, CallData *callData) +ReturnedValue ArrayCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -81,11 +82,11 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isArray"), method_isArray, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); defineDefaultProperty(QStringLiteral("join"), method_join, 1); @@ -110,7 +111,7 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx) { - bool isArray = ctx->argc() && ctx->args()[0].asArrayObject(); + bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>(); return Encode(isArray); } @@ -185,7 +186,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) r4 = arg->toQString(); ScopedObject self(scope, ctx->thisObject()); - ScopedValue length(scope, self->get(ctx->d()->engine->id_length)); + ScopedValue length(scope, self->get(ctx->d()->engine->id_length())); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); if (!r2) @@ -194,7 +195,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) QString R; // ### FIXME - if (ArrayObject *a = self->asArrayObject()) { + if (ArrayObject *a = self->as<ArrayObject>()) { ScopedValue e(scope); for (uint i = 0; i < a->getLength(); ++i) { if (i) @@ -242,7 +243,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -256,7 +257,7 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLength(len - 1); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); return result->asReturnedValue(); } @@ -282,7 +283,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) } double newLen = l + ctx->argc(); if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); else { ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); return ctx->engine()->throwRangeError(str); @@ -303,7 +304,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); return Encode(len); } @@ -354,7 +355,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -388,7 +389,7 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len - 1); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); return result->asReturnedValue(); } @@ -523,7 +524,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) } ctx->d()->strictMode = true; - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); return newArray.asReturnedValue(); } @@ -561,7 +562,7 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(newLen); else - instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); return Encode(newLen); } @@ -619,7 +620,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) return Encode(-1); } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); - Heap::SimpleArrayData *sa = static_cast<Heap::SimpleArrayData *>(instance->d()->arrayData); + Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>(); if (len > sa->len) len = sa->len; uint idx = fromIndex; diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index 4e67eb2e31..422a0de675 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -53,8 +53,8 @@ struct ArrayCtor: FunctionObject { V4_OBJECT2(ArrayCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct ArrayPrototype: ArrayObject diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 9c293e783b..53f8abf3f2 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4booleanobject_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -43,14 +44,14 @@ Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope) { } -ReturnedValue BooleanCtor::construct(Managed *m, CallData *callData) +ReturnedValue BooleanCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<BooleanCtor *>(m)->engine()); + Scope scope(static_cast<const BooleanCtor *>(m)->engine()); bool n = callData->argc ? callData->args[0].toBoolean() : false; return Encode(scope.engine->newBooleanObject(n)); } -ReturnedValue BooleanCtor::call(Managed *, CallData *callData) +ReturnedValue BooleanCtor::call(const Managed *, CallData *callData) { bool value = callData->argc ? callData->args[0].toBoolean() : 0; return Encode(value); @@ -60,11 +61,11 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); - defineDefaultProperty(engine->id_valueOf, method_valueOf); + defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_valueOf(), method_valueOf); } ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) @@ -73,7 +74,7 @@ ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) if (ctx->thisObject().isBoolean()) { result = ctx->thisObject().booleanValue(); } else { - BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); if (!thisObject) return ctx->engine()->throwTypeError(); result = thisObject->value(); @@ -87,7 +88,7 @@ ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) if (ctx->thisObject().isBoolean()) return ctx->thisObject().asReturnedValue(); - BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); if (!thisObject) return ctx->engine()->throwTypeError(); diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 903261bdce..77b5a74fde 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -53,8 +53,8 @@ struct BooleanCtor: FunctionObject { V4_OBJECT2(BooleanCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct BooleanPrototype: BooleanObject diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 9330f10780..20ed07fa2e 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -36,10 +36,12 @@ #include <qv4context_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include "qv4function_p.h" #include "qv4errorobject_p.h" +#include "qv4string_p.h" +#include "private/qqmlcontextwrapper_p.h" using namespace QV4; @@ -48,8 +50,9 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); +DEFINE_MANAGED_VTABLE(QmlContext); -Heap::CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) +Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *function, CallData *callData) { Q_ASSERT(function->function()); @@ -90,31 +93,37 @@ Heap::CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); } -Heap::CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) +Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) { - Scope scope(this); - Scoped<CallContext> c(scope, d()->engine->memoryManager->allocManaged<CallContext>(requiredMemoryForExecutionContect(f, 0))); - new (c->d()) Heap::CallContext(d()->engine, qml, f); - return c->d(); + return d()->engine->memoryManager->alloc<QmlContext>(this, qml); } - void ExecutionContext::createMutableBinding(String *name, bool deletable) { Scope scope(this); // find the right context to create the binding on - ScopedObject activation(scope, d()->engine->globalObject()); + ScopedObject activation(scope, d()->engine->globalObject); ScopedContext ctx(scope, this); while (ctx) { - if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); if (!c->activation) c->activation = scope.engine->newObject(); activation = c->activation; break; } + case Heap::ExecutionContext::Type_QmlContext: { + Heap::QmlContext *qml = static_cast<Heap::QmlContext *>(ctx->d()); + activation = qml->qml; + break; + } + default: + break; + } ctx = ctx->d()->outer; } @@ -130,7 +139,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) Heap::GlobalContext::GlobalContext(ExecutionEngine *eng) : Heap::ExecutionContext(eng, Heap::ExecutionContext::Type_GlobalContext) { - global = eng->globalObject()->d(); + global = eng->globalObject->d(); } Heap::WithContext::WithContext(ExecutionEngine *engine, QV4::Object *with) @@ -153,34 +162,23 @@ Heap::CatchContext::CatchContext(ExecutionEngine *engine, QV4::String *exception lookups = parent->lookups; compilationUnit = parent->compilationUnit; - this->exceptionVarName = exceptionVarName; + this->exceptionVarName = exceptionVarName->d(); this->exceptionValue = exceptionValue; } -Heap::CallContext::CallContext(ExecutionEngine *engine, QV4::Object *qml, QV4::FunctionObject *function) - : Heap::ExecutionContext(engine, Heap::ExecutionContext::Type_QmlContext) +Heap::QmlContext::QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml) + : Heap::ExecutionContext(outer->engine(), Heap::ExecutionContext::Type_QmlContext) { - this->function = function->d(); - callData = reinterpret_cast<CallData *>(this + 1); - callData->tag = QV4::Value::_Integer_Type; - callData->argc = 0; - callData->thisObject = Primitive::undefinedValue(); - strictMode = false; - outer = function->scope(); - - activation = qml->d(); - - if (function->function()) { - compilationUnit = function->function()->compilationUnit; - lookups = compilationUnit->runtimeLookups; - } + callData = parent->callData; + this->outer = outer->d(); + lookups = parent->lookups; + compilationUnit = parent->compilationUnit; - locals = (Value *)(this + 1); - if (function->varCount()) - std::fill(locals, locals + function->varCount(), Primitive::undefinedValue()); + this->qml = qml->d(); } + Identifier * const *CallContext::formals() const { return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() : 0; @@ -209,16 +207,28 @@ bool ExecutionContext::deleteProperty(String *name) bool hasWith = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return false; + break; + } + case Heap::ExecutionContext::Type_WithContext: { hasWith = true; ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (withObject->hasProperty(name)) return withObject->deleteProperty(name); - } else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return false; - } else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + if (global->hasProperty(name)) + return global->deleteProperty(name); + break; + } + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); ScopedFunctionObject f(scope, c->function); if (f->needsActivation() || hasWith) { @@ -227,13 +237,14 @@ bool ExecutionContext::deleteProperty(String *name) // ### throw in strict mode? return false; } - ScopedObject activation(scope, c->activation); - if (activation && activation->hasProperty(name)) - return activation->deleteProperty(name); - } else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); - if (global->hasProperty(name)) - return global->deleteProperty(name); + ScopedObject qml(scope, c->activation); + if (qml && qml->hasProperty(name)) + return qml->deleteProperty(name); + break; + } + case Heap::ExecutionContext::Type_QmlContext: + // can't delete properties on qml objects + break; } } @@ -254,7 +265,27 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) if (ctx->outer) ctx->outer->mark(engine); - if (ctx->type >= Heap::ExecutionContext::Type_CallContext) { + switch (ctx->type) { + case Heap::ExecutionContext::Type_CatchContext: { + CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); + c->exceptionVarName->mark(engine); + c->exceptionValue.mark(engine); + break; + } + case Heap::ExecutionContext::Type_WithContext: { + WithContext::Data *w = static_cast<WithContext::Data *>(ctx); + if (w->withObject) + w->withObject->mark(engine); + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); + g->global->mark(engine); + break; + } + case Heap::ExecutionContext::Type_SimpleCallContext: + break; + case Heap::ExecutionContext::Type_CallContext: { QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); ctx->callData->thisObject.mark(engine); for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->function->formalParameterCount()); ++arg) @@ -264,17 +295,13 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) if (c->activation) c->activation->mark(engine); c->function->mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_WithContext) { - WithContext::Data *w = static_cast<WithContext::Data *>(ctx); - if (w->withObject) - w->withObject->mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_CatchContext) { - CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - } else if (ctx->type == Heap::ExecutionContext::Type_GlobalContext) { - GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); - g->global->mark(engine); + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx); + g->qml->mark(engine); + break; + } } } @@ -282,57 +309,71 @@ void ExecutionContext::setProperty(String *name, const Value &value) { Scope scope(this); ScopedContext ctx(scope, this); + ScopedObject activation(scope); + for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + activation = (Object *)0; + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) { + c->exceptionValue = value; + return; + } + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (w->hasProperty(name)) { w->put(name, value); return; } - } else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext && static_cast<Heap::CatchContext *>(ctx->d())->exceptionVarName->isEqualTo(name)) { - static_cast<Heap::CatchContext *>(ctx->d())->exceptionValue = value; - return; - } else { - ScopedObject activation(scope, (Object *)0); - if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->function->function) { - uint index = c->function->function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) { - c->callData->args[c->function->formalParameterCount() - index - 1] = value; - } else { - index -= c->function->formalParameterCount(); - c->locals[index] = value; - } - return; + break; + } + case Heap::ExecutionContext::Type_GlobalContext: { + activation = static_cast<Heap::GlobalContext *>(ctx->d())->global; + break; + } + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); + if (c->function->function) { + uint index = c->function->function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->function->formalParameterCount()) { + c->callData->args[c->function->formalParameterCount() - index - 1] = value; + } else { + index -= c->function->formalParameterCount(); + c->locals[index] = value; } + return; } - activation = c->activation; - } else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - activation = static_cast<Heap::GlobalContext *>(ctx->d())->global; } + activation = c->activation; + break; + } + case Heap::ExecutionContext::Type_QmlContext: { + activation = static_cast<Heap::QmlContext *>(ctx->d())->qml; + activation->put(name, value); + return; + } + } - if (activation) { - if (ctx->d()->type == Heap::ExecutionContext::Type_QmlContext) { - activation->put(name, value); - return; - } else { - uint member = activation->internalClass()->find(name); - if (member < UINT_MAX) { - activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); - return; - } - } + if (activation) { + uint member = activation->internalClass()->find(name); + if (member < UINT_MAX) { + activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); + return; } } } - if (d()->strictMode || name->equals(d()->engine->id_this)) { + + if (d()->strictMode || name->equals(d()->engine->id_this())) { ScopedValue n(scope, name->asReturnedValue()); engine()->throwReferenceError(n); return; } - d()->engine->globalObject()->put(name, value); + d()->engine->globalObject->put(name, value); } ReturnedValue ExecutionContext::getProperty(String *name) @@ -341,14 +382,22 @@ ReturnedValue ExecutionContext::getProperty(String *name) ScopedValue v(scope); name->makeIdentifier(scope.engine); - if (name->equals(d()->engine->id_this)) + if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + hasCatchScope = true; + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return c->exceptionValue.asReturnedValue(); + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); hasWith = true; bool hasProperty = false; @@ -356,17 +405,18 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) { return v->asReturnedValue(); } - continue; + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - hasCatchScope = true; - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + bool hasProperty = false; + v = global->get(name, &hasProperty); + if (hasProperty) + return v->asReturnedValue(); + break; } - - else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); ScopedFunctionObject f(scope, c->function); if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { @@ -387,14 +437,16 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (f->function() && f->function()->isNamedExpression() && name->equals(ScopedString(scope, f->function()->name()))) return f.asReturnedValue(); + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + case Heap::ExecutionContext::Type_QmlContext: { + ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml); bool hasProperty = false; - v = global->get(name, &hasProperty); + v = qml->get(name, &hasProperty); if (hasProperty) return v->asReturnedValue(); + break; + } } } ScopedValue n(scope, name); @@ -408,14 +460,22 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Heap::Object ** *base = (Heap::Object *)0; name->makeIdentifier(scope.engine); - if (name->equals(d()->engine->id_this)) + if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { - if (ctx->d()->type == Heap::ExecutionContext::Type_WithContext) { + switch (ctx->d()->type) { + case Heap::ExecutionContext::Type_CatchContext: { + hasCatchScope = true; + Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); + if (c->exceptionVarName->isEqualTo(name->d())) + return c->exceptionValue.asReturnedValue(); + break; + } + case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); hasWith = true; bool hasProperty = false; @@ -424,48 +484,50 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Heap::Object ** *base = w->d(); return v->asReturnedValue(); } - continue; + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_CatchContext) { - hasCatchScope = true; - Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + case Heap::ExecutionContext::Type_GlobalContext: { + ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + bool hasProperty = false; + v = global->get(name, &hasProperty); + if (hasProperty) + return v->asReturnedValue(); + break; } - - else if (ctx->d()->type >= Heap::ExecutionContext::Type_CallContext) { + case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); ScopedFunctionObject f(scope, c->function); if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) { - if (index < f->formalParameterCount()) - return c->callData->args[f->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - f->formalParameterCount()].asReturnedValue(); + if (index < c->function->formalParameterCount()) + return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); + return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); } } ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; v = activation->get(name, &hasProperty); - if (hasProperty) { - if (ctx->d()->type == Heap::ExecutionContext::Type_QmlContext) - *base = activation->d(); + if (hasProperty) return v->asReturnedValue(); - } } if (f->function() && f->function()->isNamedExpression() && name->equals(ScopedString(scope, f->function()->name()))) - return c->function->asReturnedValue(); + return f.asReturnedValue(); + break; } - - else if (ctx->d()->type == Heap::ExecutionContext::Type_GlobalContext) { - ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global); + case Heap::ExecutionContext::Type_QmlContext: { + ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml); bool hasProperty = false; - v = global->get(name, &hasProperty); - if (hasProperty) + v = qml->get(name, &hasProperty); + if (hasProperty) { + *base = qml->d(); return v->asReturnedValue(); + } + break; + } } } ScopedValue n(scope, name); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 8392dd836d..8eda4ed12c 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -45,6 +45,8 @@ struct CompilationUnit; struct Function; } +struct QmlContextWrapper; +struct Identifier; struct CallContext; struct CatchContext; struct WithContext; @@ -74,9 +76,9 @@ struct ExecutionContext : Base { Type_GlobalContext = 0x1, Type_CatchContext = 0x2, Type_WithContext = 0x3, - Type_SimpleCallContext = 0x4, - Type_CallContext = 0x5, - Type_QmlContext = 0x6 + Type_QmlContext = 0x4, + Type_SimpleCallContext = 0x5, + Type_CallContext = 0x6 }; inline ExecutionContext(ExecutionEngine *engine, ContextType t); @@ -84,8 +86,8 @@ struct ExecutionContext : Base { CallData *callData; ExecutionEngine *engine; - ExecutionContext *parent; - ExecutionContext *outer; + Pointer<ExecutionContext> parent; + Pointer<ExecutionContext> outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; @@ -102,29 +104,34 @@ struct CallContext : ExecutionContext { locals = 0; activation = 0; } - CallContext(ExecutionEngine *engine, QV4::Object *qml, QV4::FunctionObject *function); - FunctionObject *function; + Pointer<FunctionObject> function; Value *locals; - Object *activation; + Pointer<Object> activation; }; struct GlobalContext : ExecutionContext { GlobalContext(ExecutionEngine *engine); - Object *global; + Pointer<Object> global; }; struct CatchContext : ExecutionContext { CatchContext(ExecutionEngine *engine, QV4::String *exceptionVarName, const Value &exceptionValue); - StringValue exceptionVarName; + Pointer<String> exceptionVarName; Value exceptionValue; }; struct WithContext : ExecutionContext { WithContext(ExecutionEngine *engine, QV4::Object *with); - Object *withObject; + Pointer<Object> withObject; }; +struct QmlContextWrapper; + +struct QmlContext : ExecutionContext { + QmlContext(QV4::ExecutionContext *outer, QV4::QmlContextWrapper *qml); + Pointer<QmlContextWrapper> qml; +}; } @@ -139,10 +146,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } - Heap::CallContext *newCallContext(FunctionObject *f, CallData *callData); + Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); Heap::WithContext *newWithContext(Object *with); Heap::CatchContext *newCatchContext(String *exceptionVarName, const Value &exceptionValue); - Heap::CallContext *newQmlContext(FunctionObject *f, Object *qml); + Heap::QmlContext *newQmlContext(QmlContextWrapper *qml); void createMutableBinding(String *name, bool deletable); @@ -160,7 +167,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed static void markObjects(Heap::Base *m, ExecutionEngine *e); - const Value &thisObject() const { + Value &thisObject() const { return d()->callData->thisObject; } int argc() const { @@ -208,6 +215,11 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; +struct QmlContext : public ExecutionContext +{ + V4_MANAGED(QmlContext, ExecutionContext) +}; + inline CallContext *ExecutionContext::asCallContext() { return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index 8a66c2cbfc..a741d61d10 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -33,6 +33,7 @@ #include "qv4dataview_p.h" #include "qv4arraybuffer_p.h" +#include "qv4string_p.h" #include "qendian.h" @@ -46,9 +47,9 @@ Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) +ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); if (!buffer) return scope.engine->throwTypeError(); @@ -69,14 +70,14 @@ ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) } -ReturnedValue DataViewCtor::call(Managed *that, CallData *callData) +ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } Heap::DataView::DataView(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->dataViewPrototype.asObject()), + : Heap::Object(e->emptyClass, e->dataViewPrototype()), buffer(0), byteLength(0), byteOffset(0) @@ -94,9 +95,9 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index 3f0c1e9e23..e98239396a 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -48,7 +48,7 @@ struct DataViewCtor : FunctionObject { struct DataView : Object { DataView(ExecutionEngine *e); - ArrayBuffer *buffer; + Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; }; @@ -59,8 +59,8 @@ struct DataViewCtor: FunctionObject { V4_OBJECT2(DataViewCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct DataView : Object diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 451ef2486d..3f45751695 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -36,6 +36,7 @@ #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" #include <QtCore/QDebug> #include <QtCore/QDateTime> @@ -628,14 +629,14 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); Heap::DateObject::DateObject(QV4::ExecutionEngine *engine, const QDateTime &date) - : Heap::Object(engine->emptyClass, engine->datePrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->datePrototype()) { - value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN()); + this->date = date.isValid() ? date.toMSecsSinceEpoch() : qSNaN(); } QDateTime DateObject::toQDateTime() const { - return ToDateTime(date().asDouble(), Qt::LocalTime); + return ToDateTime(date(), Qt::LocalTime); } DEFINE_OBJECT_VTABLE(DateCtor); @@ -645,9 +646,9 @@ Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DateCtor::construct(Managed *m, CallData *callData) +ReturnedValue DateCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<DateCtor *>(m)->engine()); + Scope scope(static_cast<const DateCtor *>(m)->engine()); double t = 0; if (callData->argc == 0) @@ -655,15 +656,16 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) else if (callData->argc == 1) { ScopedValue arg(scope, callData->args[0]); - if (DateObject *d = arg->asDateObject()) - arg = d->date(); - else + if (DateObject *d = arg->as<DateObject>()) { + t = d->date(); + } else { arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); - if (arg->isString()) - t = ParseString(arg->stringValue()->toQString()); - else - t = TimeClip(arg->toNumber()); + if (arg->isString()) + t = ParseString(arg->stringValue()->toQString()); + else + t = TimeClip(arg->toNumber()); + } } else { // d.argc > 1 @@ -683,18 +685,18 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) return Encode(scope.engine->newDateObject(Primitive::fromDouble(t))); } -ReturnedValue DateCtor::call(Managed *m, CallData *) +ReturnedValue DateCtor::call(const Managed *m, CallData *) { double t = currentTime(); - return static_cast<DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); + return static_cast<const DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); } void DatePrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(7)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7)); LocalTZA = getLocalTZA(); ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1); @@ -702,13 +704,13 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("now"), method_now, 0); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toDateString"), method_toDateString, 0); defineDefaultProperty(QStringLiteral("toTimeString"), method_toTimeString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0); defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0); - defineDefaultProperty(engine->id_valueOf, method_valueOf, 0); + defineDefaultProperty(engine->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("getTime"), method_getTime, 0); defineDefaultProperty(QStringLiteral("getYear"), method_getYear, 0); defineDefaultProperty(QStringLiteral("getFullYear"), method_getFullYear, 0); @@ -752,8 +754,8 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) double DatePrototype::getThisDate(ExecutionContext *ctx) { - if (DateObject *thisObject = ctx->thisObject().asDateObject()) - return thisObject->date().asDouble(); + if (DateObject *thisObject = ctx->thisObject().as<DateObject>()) + return thisObject->date(); else { ctx->engine()->throwTypeError(); return 0; @@ -994,8 +996,8 @@ ReturnedValue DatePrototype::method_setTime(CallContext *ctx) return ctx->engine()->throwTypeError(); double t = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(t)); - return self->date().asReturnedValue(); + self->setDate(TimeClip(t)); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) @@ -1005,175 +1007,175 @@ ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double ms = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->date().asReturnedValue(); + self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double ms = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); - self->date().setDouble(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); - return self->date().asReturnedValue(); + self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double sec = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double sec = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double min = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double min = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setHours(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double hour = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double hour = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setDate(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double date = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double date = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); double month = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double month = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); if (std::isnan(t)) t = 0; else @@ -1189,49 +1191,49 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) r = UTC(MakeDate(r, TimeWithinDay(t))); r = TimeClip(r); } - self->date().setDouble(r); - return self->date().asReturnedValue(); + self->setDate(r); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); double year = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = LocalTime(self->date().asDouble()); + double t = LocalTime(self->date()); if (std::isnan(t)) t = 0; double year = ctx->argc() ? ctx->args()[0].toNumber() : qSNaN(); double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->date().setDouble(t); - return self->date().asReturnedValue(); + self->setDate(t); + return Encode(self->date()); } ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); } @@ -1250,11 +1252,11 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits) ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) { - DateObject *self = ctx->thisObject().asDateObject(); + DateObject *self = ctx->thisObject().as<DateObject>(); if (!self) return ctx->engine()->throwTypeError(); - double t = self->date().asDouble(); + double t = self->date(); if (!std::isfinite(t)) return ctx->engine()->throwRangeError(ctx->thisObject()); @@ -1297,7 +1299,7 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); ScopedValue v(scope, O->objectValue()->get(s)); - FunctionObject *toIso = v->asFunctionObject(); + FunctionObject *toIso = v->as<FunctionObject>(); if (!toIso) return ctx->engine()->throwTypeError(); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index dad3689054..133a8d27e8 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -49,18 +49,19 @@ struct DateObject : Object { DateObject(InternalClass *ic, QV4::Object *prototype) : Object(ic, prototype) { - value = Encode(qSNaN()); + date = qSNaN(); } DateObject(QV4::ExecutionEngine *engine, const Value &date) - : Object(engine->emptyClass, engine->datePrototype.asObject()) + : Object(engine->emptyClass, engine->datePrototype()) { - value = date; + this->date = date.toNumber(); } DateObject(QV4::ExecutionEngine *engine, const QDateTime &date); - Value value; + double date; }; + struct DateCtor : FunctionObject { DateCtor(QV4::ExecutionContext *scope); }; @@ -72,19 +73,23 @@ struct DateObject: Object { Q_MANAGED_TYPE(DateObject) - Value date() const { return d()->value; } - Value &date() { return d()->value; } - void setDate(const Value &date) { d()->value = date; } + double date() const { return d()->date; } + void setDate(double date) { d()->date = date; } QDateTime toQDateTime() const; }; +template<> +inline const DateObject *Value::as() const { + return isManaged() && m && m->vtable->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; +} + struct DateCtor: FunctionObject { V4_OBJECT2(DateCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *); }; struct DatePrototype: DateObject diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 36e7a3558c..7bd5d49f3c 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -40,6 +40,7 @@ #include "qv4script_p.h" #include "qv4objectiterator_p.h" #include "qv4identifier_p.h" +#include "qv4string_p.h" #include <iostream> #include <algorithm> @@ -469,7 +470,7 @@ void Debugger::collectThrownValue(Collector *collector) void run() { Scope scope(engine); - ScopedValue v(scope, engine->exceptionValue); + ScopedValue v(scope, *engine->exceptionValue); collector->collect(QStringLiteral("exception"), v); } }; @@ -497,7 +498,7 @@ QVector<Heap::ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) Scope scope(m_engine); Scoped<CallContext> sctxt(scope, findContext(m_engine->currentContext(), frame)); - if (!sctxt || sctxt->d()->type < Heap::ExecutionContext::Type_SimpleCallContext) + if (!sctxt || sctxt->d()->type < Heap::ExecutionContext::Type_QmlContext) return types; ScopedContext it(scope, sctxt->d()); @@ -793,7 +794,7 @@ void Debugger::Collector::collect(const QString &name, const ScopedValue &value) addBoolean(name, value->booleanValue()); break; case Value::Managed_Type: - if (String *s = value->asString()) + if (const String *s = value->as<String>()) addString(name, s->toQString()); else addObject(name, value); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ba6f5a3b79..016187f488 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include <qv4engine_p.h> #include <qv4context_p.h> -#include <qv4value_inl_p.h> +#include <qv4value_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> #include <qv4objectiterator_p.h> @@ -48,7 +48,7 @@ #include <qv4regexp_p.h> #include <qv4variantobject_p.h> #include <qv4runtime_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include <qv4dateobject_p.h> #include <qv4jsonobject_p.h> @@ -59,7 +59,6 @@ #include "qv4executableallocator_p.h" #include "qv4sequenceobject_p.h" #include "qv4qobjectwrapper_p.h" -#include "qv4qmlextensions_p.h" #include "qv4memberdata_p.h" #include "qv4arraybuffer_p.h" #include "qv4dataview_p.h" @@ -192,6 +191,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : current(0) + , hasException(false) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -206,13 +206,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_engineId(engineSerial.fetchAndAddOrdered(1)) , regExpCache(0) , m_multiplyWrappedQObjects(0) - , m_qmlExtensions(0) { MemoryManager::GCBlocker gcBlocker(memoryManager); - exceptionValue = Encode::undefined(); - hasException = false; - if (!factory) { #ifdef V4_ENABLE_JIT @@ -236,6 +232,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStackBase = (Value *)jsStack->base(); jsStackTop = jsStackBase; + exceptionValue = jsAlloca(1); + globalObject = static_cast<Object *>(jsAlloca(1)); + jsObjects = jsAlloca(NJSObjects); + typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes)); + typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes)); + jsStrings = jsAlloca(NJSStrings); + #ifdef V4_USE_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit); #endif @@ -246,208 +249,208 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) if (!recheckCStackLimits()) qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize); - Scope scope(this); - identifierTable = new IdentifierTable(this); classPool = new InternalClassPool; emptyClass = new (classPool) InternalClass(this); - id_empty = newIdentifier(QString()); - id_undefined = newIdentifier(QStringLiteral("undefined")); - id_null = newIdentifier(QStringLiteral("null")); - id_true = newIdentifier(QStringLiteral("true")); - id_false = newIdentifier(QStringLiteral("false")); - id_boolean = newIdentifier(QStringLiteral("boolean")); - id_number = newIdentifier(QStringLiteral("number")); - id_string = newIdentifier(QStringLiteral("string")); - id_object = newIdentifier(QStringLiteral("object")); - id_function = newIdentifier(QStringLiteral("function")); - id_length = newIdentifier(QStringLiteral("length")); - id_prototype = newIdentifier(QStringLiteral("prototype")); - id_constructor = newIdentifier(QStringLiteral("constructor")); - id_arguments = newIdentifier(QStringLiteral("arguments")); - id_caller = newIdentifier(QStringLiteral("caller")); - id_callee = newIdentifier(QStringLiteral("callee")); - id_this = newIdentifier(QStringLiteral("this")); - id___proto__ = newIdentifier(QStringLiteral("__proto__")); - id_enumerable = newIdentifier(QStringLiteral("enumerable")); - id_configurable = newIdentifier(QStringLiteral("configurable")); - id_writable = newIdentifier(QStringLiteral("writable")); - id_value = newIdentifier(QStringLiteral("value")); - id_get = newIdentifier(QStringLiteral("get")); - id_set = newIdentifier(QStringLiteral("set")); - id_eval = newIdentifier(QStringLiteral("eval")); - id_uintMax = newIdentifier(QStringLiteral("4294967295")); - id_name = newIdentifier(QStringLiteral("name")); - id_index = newIdentifier(QStringLiteral("index")); - id_input = newIdentifier(QStringLiteral("input")); - id_toString = newIdentifier(QStringLiteral("toString")); - id_destroy = newIdentifier(QStringLiteral("destroy")); - id_valueOf = newIdentifier(QStringLiteral("valueOf")); - id_byteLength = newIdentifier(QStringLiteral("byteLength")); - id_byteOffset = newIdentifier(QStringLiteral("byteOffset")); - id_buffer = newIdentifier(QStringLiteral("buffer")); - id_lastIndex = newIdentifier(QStringLiteral("lastIndex")); - - objectPrototype = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); - - arrayClass = emptyClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable); - arrayPrototype = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype.asObject()); - - InternalClass *argsClass = emptyClass->addMember(id_length, Attr_NotEnumerable); - argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable); - strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - - m_globalObject = newObject(); - Q_ASSERT(globalObject()->d()->vtable); + jsStrings[String_Empty] = newIdentifier(QString()); + jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); + jsStrings[String_null] = newIdentifier(QStringLiteral("null")); + jsStrings[String_true] = newIdentifier(QStringLiteral("true")); + jsStrings[String_false] = newIdentifier(QStringLiteral("false")); + jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean")); + jsStrings[String_number] = newIdentifier(QStringLiteral("number")); + jsStrings[String_string] = newIdentifier(QStringLiteral("string")); + jsStrings[String_object] = newIdentifier(QStringLiteral("object")); + jsStrings[String_function] = newIdentifier(QStringLiteral("function")); + jsStrings[String_length] = newIdentifier(QStringLiteral("length")); + jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype")); + jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor")); + jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments")); + jsStrings[String_caller] = newIdentifier(QStringLiteral("caller")); + jsStrings[String_callee] = newIdentifier(QStringLiteral("callee")); + jsStrings[String_this] = newIdentifier(QStringLiteral("this")); + jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__")); + jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable")); + jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable")); + jsStrings[String_writable] = newIdentifier(QStringLiteral("writable")); + jsStrings[String_value] = newIdentifier(QStringLiteral("value")); + jsStrings[String_get] = newIdentifier(QStringLiteral("get")); + jsStrings[String_set] = newIdentifier(QStringLiteral("set")); + jsStrings[String_eval] = newIdentifier(QStringLiteral("eval")); + jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295")); + jsStrings[String_name] = newIdentifier(QStringLiteral("name")); + jsStrings[String_index] = newIdentifier(QStringLiteral("index")); + jsStrings[String_input] = newIdentifier(QStringLiteral("input")); + jsStrings[String_toString] = newIdentifier(QStringLiteral("toString")); + jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy")); + jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf")); + jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength")); + jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset")); + jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); + jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); + + jsObjects[ObjectProto] = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0); + + arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + jsObjects[ArrayProto] = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype()); + + InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable); + argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); + strictArgumentsObjectClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + + *static_cast<Value *>(globalObject) = newObject(); + Q_ASSERT(globalObject->d()->vtable); initRootContext(); - stringPrototype = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype.asObject()); - numberPrototype = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype.asObject()); - booleanPrototype = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype.asObject()); - datePrototype = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype.asObject()); + jsObjects[StringProto] = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype()); + jsObjects[NumberProto] = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype()); + jsObjects[BooleanProto] = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype()); + jsObjects[DateProto] = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype()); uint index; - InternalClass *functionProtoClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable, &index); + InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - functionPrototype = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype.asObject()); - functionClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); + jsObjects[FunctionProto] = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype()); + functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - simpleScriptFunctionClass = functionClass->addMember(id_name, Attr_ReadOnly, &index); + simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name); - simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length, Attr_ReadOnly, &index); + simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length); - protoClass = emptyClass->addMember(id_constructor, Attr_NotEnumerable, &index); + protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); - regExpPrototype = memoryManager->alloc<RegExpPrototype>(this); - regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index); + jsObjects[RegExpProto] = memoryManager->alloc<RegExpPrototype>(this); + regExpExecArrayClass = arrayClass->addMember(id_index(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); - regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index); + regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - errorPrototype = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype.asObject()); - evalErrorPrototype = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype.asObject()); - rangeErrorPrototype = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype.asObject()); - referenceErrorPrototype = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype.asObject()); - syntaxErrorPrototype = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype.asObject()); - typeErrorPrototype = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype.asObject()); - uRIErrorPrototype = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype.asObject()); + jsObjects[ErrorProto] = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype()); + jsObjects[EvalErrorProto] = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype()); - variantPrototype = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype.asObject()); - Q_ASSERT(variantPrototype.asObject()->prototype() == objectPrototype.asObject()->d()); + jsObjects[VariantProto] = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype()); + Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - sequencePrototype = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype.asObject())); + Scope scope(this); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype())); ScopedContext global(scope, rootContext()); - objectCtor = memoryManager->alloc<ObjectCtor>(global); - stringCtor = memoryManager->alloc<StringCtor>(global); - numberCtor = memoryManager->alloc<NumberCtor>(global); - booleanCtor = memoryManager->alloc<BooleanCtor>(global); - arrayCtor = memoryManager->alloc<ArrayCtor>(global); - functionCtor = memoryManager->alloc<FunctionCtor>(global); - dateCtor = memoryManager->alloc<DateCtor>(global); - regExpCtor = memoryManager->alloc<RegExpCtor>(global); - errorCtor = memoryManager->alloc<ErrorCtor>(global); - evalErrorCtor = memoryManager->alloc<EvalErrorCtor>(global); - rangeErrorCtor = memoryManager->alloc<RangeErrorCtor>(global); - referenceErrorCtor = memoryManager->alloc<ReferenceErrorCtor>(global); - syntaxErrorCtor = memoryManager->alloc<SyntaxErrorCtor>(global); - typeErrorCtor = memoryManager->alloc<TypeErrorCtor>(global); - uRIErrorCtor = memoryManager->alloc<URIErrorCtor>(global); - - static_cast<ObjectPrototype *>(objectPrototype.asObject())->init(this, objectCtor.asObject()); - static_cast<StringPrototype *>(stringPrototype.asObject())->init(this, stringCtor.asObject()); - static_cast<NumberPrototype *>(numberPrototype.asObject())->init(this, numberCtor.asObject()); - static_cast<BooleanPrototype *>(booleanPrototype.asObject())->init(this, booleanCtor.asObject()); - static_cast<ArrayPrototype *>(arrayPrototype.asObject())->init(this, arrayCtor.asObject()); - static_cast<DatePrototype *>(datePrototype.asObject())->init(this, dateCtor.asObject()); - static_cast<FunctionPrototype *>(functionPrototype.asObject())->init(this, functionCtor.asObject()); - static_cast<RegExpPrototype *>(regExpPrototype.asObject())->init(this, regExpCtor.asObject()); - static_cast<ErrorPrototype *>(errorPrototype.asObject())->init(this, errorCtor.asObject()); - static_cast<EvalErrorPrototype *>(evalErrorPrototype.asObject())->init(this, evalErrorCtor.asObject()); - static_cast<RangeErrorPrototype *>(rangeErrorPrototype.asObject())->init(this, rangeErrorCtor.asObject()); - static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype.asObject())->init(this, referenceErrorCtor.asObject()); - static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype.asObject())->init(this, syntaxErrorCtor.asObject()); - static_cast<TypeErrorPrototype *>(typeErrorPrototype.asObject())->init(this, typeErrorCtor.asObject()); - static_cast<URIErrorPrototype *>(uRIErrorPrototype.asObject())->init(this, uRIErrorCtor.asObject()); - - static_cast<VariantPrototype *>(variantPrototype.asObject())->init(); - sequencePrototype.cast<SequencePrototype>()->init(); + jsObjects[Object_Ctor] = memoryManager->alloc<ObjectCtor>(global); + jsObjects[String_Ctor] = memoryManager->alloc<StringCtor>(global); + jsObjects[Number_Ctor] = memoryManager->alloc<NumberCtor>(global); + jsObjects[Boolean_Ctor] = memoryManager->alloc<BooleanCtor>(global); + jsObjects[Array_Ctor] = memoryManager->alloc<ArrayCtor>(global); + jsObjects[Function_Ctor] = memoryManager->alloc<FunctionCtor>(global); + jsObjects[Date_Ctor] = memoryManager->alloc<DateCtor>(global); + jsObjects[RegExp_Ctor] = memoryManager->alloc<RegExpCtor>(global); + jsObjects[Error_Ctor] = memoryManager->alloc<ErrorCtor>(global); + jsObjects[EvalError_Ctor] = memoryManager->alloc<EvalErrorCtor>(global); + jsObjects[RangeError_Ctor] = memoryManager->alloc<RangeErrorCtor>(global); + jsObjects[ReferenceError_Ctor] = memoryManager->alloc<ReferenceErrorCtor>(global); + jsObjects[SyntaxError_Ctor] = memoryManager->alloc<SyntaxErrorCtor>(global); + jsObjects[TypeError_Ctor] = memoryManager->alloc<TypeErrorCtor>(global); + jsObjects[URIError_Ctor] = memoryManager->alloc<URIErrorCtor>(global); + + static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor()); + static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor()); + static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor()); + static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor()); + static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor()); + static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor()); + static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor()); + static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor()); + static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor()); + static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor()); + static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(this, rangeErrorCtor()); + static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(this, referenceErrorCtor()); + static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor()); + static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor()); + static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor()); + + static_cast<VariantPrototype *>(variantPrototype())->init(); + sequencePrototype()->cast<SequencePrototype>()->init(); // typed arrays - arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(global); - arrayBufferPrototype = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype.asObject()); - static_cast<ArrayBufferPrototype *>(arrayBufferPrototype.asObject())->init(this, arrayBufferCtor.asObject()); + jsObjects[ArrayBuffer_Ctor] = memoryManager->alloc<ArrayBufferCtor>(global); + jsObjects[ArrayBufferProto] = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype()); + static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor()); - dataViewCtor = memoryManager->alloc<DataViewCtor>(global); - dataViewPrototype = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype.asObject()); - static_cast<DataViewPrototype *>(dataViewPrototype.asObject())->init(this, dataViewCtor.asObject()); + jsObjects[DataView_Ctor] = memoryManager->alloc<DataViewCtor>(global); + jsObjects[DataViewProto] = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype()); + static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor()); + jsObjects[ValueTypeProto] = (Heap::Base *) 0; for (int i = 0; i < Heap::TypedArray::NTypes; ++i) { - typedArrayCtors[i] = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); - typedArrayPrototype[i] = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); - typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].asObject())); + static_cast<Value &>(typedArrayCtors[i]) = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i)); + static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i)); + typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>())); } // // set up the global object // - rootContext()->global = globalObject()->d(); - rootContext()->callData->thisObject = globalObject(); - Q_ASSERT(globalObject()->d()->vtable); - - globalObject()->defineDefaultProperty(QStringLiteral("Object"), objectCtor); - globalObject()->defineDefaultProperty(QStringLiteral("String"), stringCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Number"), numberCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Boolean"), booleanCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Array"), arrayCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Function"), functionCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Date"), dateCtor); - globalObject()->defineDefaultProperty(QStringLiteral("RegExp"), regExpCtor); - globalObject()->defineDefaultProperty(QStringLiteral("Error"), errorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("EvalError"), evalErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("RangeError"), rangeErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("ReferenceError"), referenceErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("SyntaxError"), syntaxErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor); - globalObject()->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor); - - globalObject()->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor); - globalObject()->defineDefaultProperty(QStringLiteral("DataView"), dataViewCtor); + rootContext()->d()->global = globalObject->d(); + rootContext()->d()->callData->thisObject = globalObject; + Q_ASSERT(globalObject->d()->vtable); + + globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor()); + globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Date"), *dateCtor()); + globalObject->defineDefaultProperty(QStringLiteral("RegExp"), *regExpCtor()); + globalObject->defineDefaultProperty(QStringLiteral("Error"), *errorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("EvalError"), *evalErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("RangeError"), *rangeErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), *referenceErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor()); + globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor()); + + globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor()); + globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor()); ScopedString str(scope); for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - globalObject()->defineDefaultProperty((str = typedArrayCtors[i].asFunctionObject()->name())->toQString(), typedArrayCtors[i]); + globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]); ScopedObject o(scope); - globalObject()->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this))); - globalObject()->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this))); + globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this))); + globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this))); - globalObject()->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); - globalObject()->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); - globalObject()->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); + globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); + globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); + globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); - evalFunction = memoryManager->alloc<EvalFunction>(global); - globalObject()->defineDefaultProperty(QStringLiteral("eval"), (o = evalFunction)); + jsObjects[Eval_Function] = memoryManager->alloc<EvalFunction>(global); + globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction()); - globalObject()->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); - globalObject()->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); - globalObject()->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); - globalObject()->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); - globalObject()->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); - globalObject()->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1); - globalObject()->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1); - globalObject()->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1); - globalObject()->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1); - globalObject()->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); + globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); + globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); + globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); + globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); + globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); + globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1); + globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1); + globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1); + globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1); + globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); ScopedString name(scope, newString(QStringLiteral("thrower"))); - thrower = BuiltinFunction::create(global, name, ::throwTypeError); + jsObjects[ThrowerObject] = BuiltinFunction::create(global, name, ::throwTypeError); } ExecutionEngine::~ExecutionEngine() @@ -466,7 +469,6 @@ ExecutionEngine::~ExecutionEngine() foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits) unit->unlink(); - delete m_qmlExtensions; emptyClass->destroy(); delete classPool; delete bumperPointerAllocator; @@ -499,10 +501,10 @@ void ExecutionEngine::initRootContext() r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1); r->d()->callData->tag = QV4::Value::_Integer_Type; r->d()->callData->argc = 0; - r->d()->callData->thisObject = globalObject(); + r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); - m_rootContext = r->d(); + jsObjects[RootContect] = r; } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -514,7 +516,7 @@ Heap::ExecutionContext *ExecutionEngine::pushGlobalContext() { Scope scope(this); Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this)); - g->d()->callData = rootContext()->callData; + g->d()->callData = rootContext()->d()->callData; Q_ASSERT(currentContext() == g->d()); return g->d(); @@ -546,10 +548,10 @@ Heap::String *ExecutionEngine::newIdentifier(const QString &text) return identifierTable->insertString(text); } -Heap::Object *ExecutionEngine::newStringObject(const Value &value) +Heap::Object *ExecutionEngine::newStringObject(const String *string) { Scope scope(this); - Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, value)); + Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, string)); return object->d(); } @@ -648,7 +650,7 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re) Heap::Object *ExecutionEngine::newErrorObject(const Value &value) { Scope scope(this); - ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype.asObject(), value)); + ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype(), value)); return object->d(); } @@ -718,7 +720,7 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) return obj->d(); } -Heap::Object *ExecutionEngine::qmlContextObject() const +Heap::QmlContextWrapper *ExecutionEngine::qmlContextObject() const { Heap::ExecutionContext *ctx = currentContext(); @@ -735,8 +737,20 @@ Heap::Object *ExecutionEngine::qmlContextObject() const if (ctx->type != Heap::ExecutionContext::Type_QmlContext) return 0; - Q_ASSERT(static_cast<Heap::CallContext *>(ctx)->activation); - return static_cast<Heap::CallContext *>(ctx)->activation; + Q_ASSERT(static_cast<Heap::QmlContext *>(ctx)->qml); + return static_cast<Heap::QmlContext *>(ctx)->qml; +} + +QObject *ExecutionEngine::qmlScopeObject() const +{ + return qmlContextObject()->scopeObject; +} + +QQmlContextData *ExecutionEngine::callingQmlContext() const +{ + Heap::QmlContextWrapper *w = qmlContextObject(); + + return w ? w->context.contextData() : 0; } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -772,7 +786,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const StackFrame frame; frame.source = globalCode->sourceFile(); frame.function = globalCode->name()->toQString(); - frame.line = rootContext()->lineNumber; + frame.line = rootContext()->d()->lineNumber; frame.column = -1; stack.append(frame); @@ -884,8 +898,6 @@ void ExecutionEngine::markObjects() { identifierTable->mark(this); - globalObject()->mark(this); - for (int i = 0; i < nArgumentsAccessors; ++i) { const Property &pd = argumentsAccessors[i]; if (Heap::FunctionObject *getter = pd.getter()) @@ -904,93 +916,6 @@ void ExecutionEngine::markObjects() c = c->parent; } - id_empty->mark(this); - id_undefined->mark(this); - id_null->mark(this); - id_true->mark(this); - id_false->mark(this); - id_boolean->mark(this); - id_number->mark(this); - id_string->mark(this); - id_object->mark(this); - id_function->mark(this); - id_length->mark(this); - id_prototype->mark(this); - id_constructor->mark(this); - id_arguments->mark(this); - id_caller->mark(this); - id_callee->mark(this); - id_this->mark(this); - id___proto__->mark(this); - id_enumerable->mark(this); - id_configurable->mark(this); - id_writable->mark(this); - id_value->mark(this); - id_get->mark(this); - id_set->mark(this); - id_eval->mark(this); - id_uintMax->mark(this); - id_name->mark(this); - id_index->mark(this); - id_input->mark(this); - id_toString->mark(this); - id_destroy->mark(this); - id_valueOf->mark(this); - id_byteLength->mark(this); - id_byteOffset->mark(this); - id_buffer->mark(this); - id_lastIndex->mark(this); - - objectCtor.mark(this); - stringCtor.mark(this); - numberCtor.mark(this); - booleanCtor.mark(this); - arrayCtor.mark(this); - functionCtor.mark(this); - dateCtor.mark(this); - regExpCtor.mark(this); - errorCtor.mark(this); - evalErrorCtor.mark(this); - rangeErrorCtor.mark(this); - referenceErrorCtor.mark(this); - syntaxErrorCtor.mark(this); - typeErrorCtor.mark(this); - uRIErrorCtor.mark(this); - arrayBufferCtor.mark(this); - dataViewCtor.mark(this); - for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - typedArrayCtors[i].mark(this); - - objectPrototype.mark(this); - arrayPrototype.mark(this); - stringPrototype.mark(this); - numberPrototype.mark(this); - booleanPrototype.mark(this); - datePrototype.mark(this); - functionPrototype.mark(this); - regExpPrototype.mark(this); - errorPrototype.mark(this); - evalErrorPrototype.mark(this); - rangeErrorPrototype.mark(this); - referenceErrorPrototype.mark(this); - syntaxErrorPrototype.mark(this); - typeErrorPrototype.mark(this); - uRIErrorPrototype.mark(this); - variantPrototype.mark(this); - sequencePrototype.mark(this); - - arrayBufferPrototype.mark(this); - dataViewPrototype.mark(this); - for (int i = 0; i < Heap::TypedArray::NTypes; ++i) - typedArrayPrototype[i].mark(this); - - exceptionValue.mark(this); - - thrower->mark(this); - - if (m_qmlExtensions) - m_qmlExtensions->markObjects(this); - classPool->markObjects(this); for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); @@ -998,13 +923,6 @@ void ExecutionEngine::markObjects() (*it)->markObjects(this); } -QmlExtensions *ExecutionEngine::qmlExtensions() -{ - if (!m_qmlExtensions) - m_qmlExtensions = new QmlExtensions; - return m_qmlExtensions; -} - ReturnedValue ExecutionEngine::throwError(const Value &value) { // we can get in here with an exception already set, as the runtime @@ -1015,7 +933,7 @@ ReturnedValue ExecutionEngine::throwError(const Value &value) return Encode::undefined(); hasException = true; - exceptionValue = value; + *exceptionValue = value; QV4::Scope scope(this); QV4::Scoped<ErrorObject> error(scope, value); if (!!error) @@ -1036,8 +954,8 @@ ReturnedValue ExecutionEngine::catchException(StackTrace *trace) *trace = exceptionStackTrace; exceptionStackTrace.clear(); hasException = false; - ReturnedValue res = exceptionValue.asReturnedValue(); - exceptionValue = Primitive::emptyValue(); + ReturnedValue res = exceptionValue->asReturnedValue(); + *exceptionValue = Primitive::emptyValue(); return res; } @@ -1170,7 +1088,7 @@ bool ExecutionEngine::recheckCStackLimits() typedef QSet<QV4::Heap::Object *> V4ObjectSet; static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects); static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value); -static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4ObjectSet *visitedObjects = 0); +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = 0); static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result); @@ -1193,7 +1111,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int Q_ASSERT (!value.isEmpty()); QV4::Scope scope(e); - if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) + if (const QV4::VariantObject *v = value.as<QV4::VariantObject>()) return v->d()->data; if (typeHint == QVariant::Bool) @@ -1205,10 +1123,10 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int if (typeHint == qMetaTypeId<QJSValue>()) return QVariant::fromValue(QJSValue(e, value.asReturnedValue())); - if (value.asObject()) { + if (value.as<Object>()) { QV4::ScopedObject object(scope, value); if (typeHint == QMetaType::QJsonObject - && !value.asArrayObject() && !value.asFunctionObject()) { + && !value.as<ArrayObject>() && !value.as<FunctionObject>()) { return QVariant::fromValue(QV4::JsonObject::toJsonObject(object)); } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) { return qVariantFromValue<QObject *>(wrapper->object()); @@ -1224,7 +1142,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return QV4::SequencePrototype::toVariant(object); } - if (value.asArrayObject()) { + if (value.as<ArrayObject>()) { QV4::ScopedArrayObject a(scope, value); if (typeHint == qMetaTypeId<QList<QObject *> >()) { QList<QObject *> list; @@ -1262,11 +1180,11 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return value.asDouble(); if (value.isString()) return value.stringValue()->toQString(); - if (QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) + if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>()) return ld->d()->locale; - if (QV4::DateObject *d = value.asDateObject()) + if (const QV4::DateObject *d = value.as<DateObject>()) return d->toQDateTime(); - if (QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) + if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) return d->asByteArray(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! @@ -1282,7 +1200,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return objectToVariant(e, o, visitedObjects); } -static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4ObjectSet *visitedObjects) +static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects) { Q_ASSERT(o); @@ -1293,7 +1211,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). - if (o->asArrayObject()) + if (o->as<ArrayObject>()) return QVariantList(); return QVariantMap(); } @@ -1301,7 +1219,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec QVariant result; - if (o->asArrayObject()) { + if (o->as<ArrayObject>()) { QV4::Scope scope(e); QV4::ScopedArrayObject a(scope, o->asReturnedValue()); QV4::ScopedValue v(scope); @@ -1314,7 +1232,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, QV4::Object *o, V4Objec } result = list; - } else if (!o->asFunctionObject()) { + } else if (!o->as<FunctionObject>()) { QVariantMap map; QV4::Scope scope(e); QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly); @@ -1492,7 +1410,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return QV4::Encode(newVariantObject(variant)); } -QVariantMap ExecutionEngine::variantMapFromJS(Object *o) +QVariantMap ExecutionEngine::variantMapFromJS(const Object *o) { return objectToVariant(this, o).toMap(); } @@ -1625,93 +1543,90 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return 0; } -void ExecutionEngine::assertObjectBelongsToEngine(const Value &v) +void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject) { - Q_UNUSED(v); - Q_ASSERT(!v.isObject() || v.objectValue()->engine() == this); - Q_UNUSED(v); + Q_ASSERT(!baseObject.vtable->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this); + Q_UNUSED(baseObject); } // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. -bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *data) +bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) { - QV4::Scope scope(this); - // check if it's one of the types we know switch (QMetaType::Type(type)) { case QMetaType::Bool: - *reinterpret_cast<bool*>(data) = value.toBoolean(); + *reinterpret_cast<bool*>(data) = value->toBoolean(); return true; case QMetaType::Int: - *reinterpret_cast<int*>(data) = value.toInt32(); + *reinterpret_cast<int*>(data) = value->toInt32(); return true; case QMetaType::UInt: - *reinterpret_cast<uint*>(data) = value.toUInt32(); + *reinterpret_cast<uint*>(data) = value->toUInt32(); return true; case QMetaType::LongLong: - *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger()); + *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger()); return true; case QMetaType::ULongLong: - *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger()); + *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger()); return true; case QMetaType::Double: - *reinterpret_cast<double*>(data) = value.toNumber(); + *reinterpret_cast<double*>(data) = value->toNumber(); return true; case QMetaType::QString: - if (value.isUndefined() || value.isNull()) + if (value->isUndefined() || value->isNull()) *reinterpret_cast<QString*>(data) = QString(); else - *reinterpret_cast<QString*>(data) = value.toQString(); + *reinterpret_cast<QString*>(data) = value->toQString(); return true; case QMetaType::Float: - *reinterpret_cast<float*>(data) = value.toNumber(); + *reinterpret_cast<float*>(data) = value->toNumber(); return true; case QMetaType::Short: - *reinterpret_cast<short*>(data) = short(value.toInt32()); + *reinterpret_cast<short*>(data) = short(value->toInt32()); return true; case QMetaType::UShort: - *reinterpret_cast<unsigned short*>(data) = value.toUInt16(); + *reinterpret_cast<unsigned short*>(data) = value->toUInt16(); return true; case QMetaType::Char: - *reinterpret_cast<char*>(data) = char(value.toInt32()); + *reinterpret_cast<char*>(data) = char(value->toInt32()); return true; case QMetaType::UChar: - *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32()); + *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32()); return true; case QMetaType::QChar: - if (value.isString()) { - QString str = value.stringValue()->toQString(); + if (value->isString()) { + QString str = value->stringValue()->toQString(); *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); } else { - *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16())); + *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16())); } return true; case QMetaType::QDateTime: - if (QV4::DateObject *d = value.asDateObject()) { + if (const QV4::DateObject *d = value->as<DateObject>()) { *reinterpret_cast<QDateTime *>(data) = d->toQDateTime(); return true; } break; case QMetaType::QDate: - if (QV4::DateObject *d = value.asDateObject()) { + if (const QV4::DateObject *d = value->as<DateObject>()) { *reinterpret_cast<QDate *>(data) = d->toQDateTime().date(); return true; } break; case QMetaType::QRegExp: - if (QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) { + if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) { *reinterpret_cast<QRegExp *>(data) = r->toQRegExp(); return true; } break; case QMetaType::QObjectStar: { - QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>(); - if (qobjectWrapper || value.isNull()) { - *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(scope.engine, value); + const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>(); + if (qobjectWrapper || value->isNull()) { + *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value); return true; } break; } case QMetaType::QStringList: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<QV4::ArrayObject>(); if (a) { *reinterpret_cast<QStringList *>(data) = a->toQStringList(); return true; @@ -1719,15 +1634,15 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da break; } case QMetaType::QVariantList: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<QV4::ArrayObject>(); if (a) { - *reinterpret_cast<QVariantList *>(data) = scope.engine->toVariant(a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList(); + *reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList(); return true; } break; } case QMetaType::QVariantMap: { - QV4::ScopedObject o(scope, value); + const QV4::Object *o = value->as<QV4::Object>(); if (o) { *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o); return true; @@ -1735,20 +1650,19 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da break; } case QMetaType::QVariant: - *reinterpret_cast<QVariant*>(data) = scope.engine->toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false); + *reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false); return true; case QMetaType::QJsonValue: - *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value); + *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value); return true; case QMetaType::QJsonObject: { - QV4::ScopedObject o(scope, value); - *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(o); + *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>()); return true; } case QMetaType::QJsonArray: { - QV4::ScopedArrayObject a(scope, value); + const QV4::ArrayObject *a = value->as<ArrayObject>(); if (a) { - *reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(a); + *reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a); return true; } break; @@ -1758,7 +1672,7 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da } { - QV4::Scoped<QV4::QQmlValueTypeWrapper> vtw(scope, value); + const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>(); if (vtw && vtw->typeId() == type) { return vtw->toGadget(data); } @@ -1783,21 +1697,22 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da } #endif - // Try to use magic; for compatibility with qscriptvalue_cast. + // Try to use magic; for compatibility with qjsvalue_cast. QByteArray name = QMetaType::typeName(type); - if (convertToNativeQObject(this, value, name, reinterpret_cast<void* *>(data))) + if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data))) return true; - if (value.as<QV4::VariantObject>() && name.endsWith('*')) { + if (value->as<QV4::VariantObject>() && name.endsWith('*')) { int valueType = QMetaType::type(name.left(name.size()-1)); - QVariant &var = value.as<QV4::VariantObject>()->d()->data; + QVariant &var = value->as<QV4::VariantObject>()->d()->data; if (valueType == var.userType()) { // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); return true; - } else if (value.isObject()) { + } else if (value->isObject()) { // Look in the prototype chain. - QV4::ScopedObject proto(scope, value.objectValue()->prototype()); + QV4::Scope scope(this); + QV4::ScopedObject proto(scope, value->objectValue()->prototype()); while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { @@ -1807,7 +1722,7 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da else if (proto->as<QV4::QObjectWrapper>()) { QByteArray className = name.left(name.size()-1); QV4::ScopedObject p(scope, proto.getPointer()); - if (QObject *qobject = qtObjectFromJS(scope.engine, p)) + if (QObject *qobject = qtObjectFromJS(this, p)) canCast = qobject->qt_metacast(className) != 0; } if (canCast) { @@ -1821,11 +1736,11 @@ bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *da proto = proto->prototype(); } } - } else if (value.isNull() && name.endsWith('*')) { + } else if (value->isNull() && name.endsWith('*')) { *reinterpret_cast<void* *>(data) = 0; return true; } else if (type == qMetaTypeId<QJSValue>()) { - *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value.asReturnedValue()); + *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue()); return true; } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index c0c88abaa5..d4bcf363a2 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -37,6 +37,7 @@ #include "private/qv4isel_p.h" #include "qv4managed_p.h" #include "qv4context_p.h" +#include "qv4internalclass_p.h" #include <private/qintrusivelist_p.h> namespace WTF { @@ -50,6 +51,7 @@ class QV8Engine; class QQmlError; class QJSEngine; class QQmlEngine; +class QQmlContextData; namespace QV4 { namespace Debugging { @@ -80,8 +82,6 @@ public: Value *jsStackTop; quint32 hasException; - Heap::GlobalContext *m_rootContext; - Heap::GlobalContext *rootContext() const { return m_rootContext; } MemoryManager *memoryManager; ExecutableAllocator *executableAllocator; @@ -106,14 +106,19 @@ public: --jsStackTop; return jsStackTop->heapObject(); } + Value *jsAlloca(int nValues) { + Value *ptr = jsStackTop; + jsStackTop = ptr + nValues; + memset(ptr, 0, nValues*sizeof(Value)); + return ptr; + } IdentifierTable *identifierTable; QV4::Debugging::Debugger *debugger; QV4::Profiling::Profiler *profiler; - Value m_globalObject; - Object *globalObject() { return reinterpret_cast<Object *>(&m_globalObject); } + Object *globalObject; Function *globalCode; @@ -121,47 +126,97 @@ public: QQmlEngine *qmlEngine() const; QV8Engine *v8Engine; - Value objectCtor; - Value stringCtor; - Value numberCtor; - Value booleanCtor; - Value arrayCtor; - Value functionCtor; - Value dateCtor; - Value regExpCtor; - Value errorCtor; - Value evalErrorCtor; - Value rangeErrorCtor; - Value referenceErrorCtor; - Value syntaxErrorCtor; - Value typeErrorCtor; - Value uRIErrorCtor; - Value arrayBufferCtor; - Value dataViewCtor; - enum { NTypedArrayTypes = 9 }; // avoid header dependency - Value typedArrayCtors[NTypedArrayTypes]; - - Value objectPrototype; - Value arrayPrototype; - Value stringPrototype; - Value numberPrototype; - Value booleanPrototype; - Value datePrototype; - Value functionPrototype; - Value regExpPrototype; - Value errorPrototype; - Value evalErrorPrototype; - Value rangeErrorPrototype; - Value referenceErrorPrototype; - Value syntaxErrorPrototype; - Value typeErrorPrototype; - Value uRIErrorPrototype; - Value variantPrototype; - Value sequencePrototype; - - Value arrayBufferPrototype; - Value dataViewPrototype; - Value typedArrayPrototype[NTypedArrayTypes]; // TypedArray::NValues, avoid including the header here + enum JSObjects { + RootContect, + ObjectProto, + ArrayProto, + StringProto, + NumberProto, + BooleanProto, + DateProto, + FunctionProto, + RegExpProto, + ErrorProto, + EvalErrorProto, + RangeErrorProto, + ReferenceErrorProto, + SyntaxErrorProto, + TypeErrorProto, + URIErrorProto, + VariantProto, + SequenceProto, + ArrayBufferProto, + DataViewProto, + ValueTypeProto, + + Object_Ctor, + String_Ctor, + Number_Ctor, + Boolean_Ctor, + Array_Ctor, + Function_Ctor, + Date_Ctor, + RegExp_Ctor, + Error_Ctor, + EvalError_Ctor, + RangeError_Ctor, + ReferenceError_Ctor, + SyntaxError_Ctor, + TypeError_Ctor, + URIError_Ctor, + ArrayBuffer_Ctor, + DataView_Ctor, + + Eval_Function, + ThrowerObject, + NJSObjects + }; + Value *jsObjects; + enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency + + GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContect); } + FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); } + FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); } + FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); } + FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); } + FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); } + FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); } + FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); } + FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); } + FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); } + FunctionObject *evalErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + EvalError_Ctor); } + FunctionObject *rangeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RangeError_Ctor); } + FunctionObject *referenceErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ReferenceError_Ctor); } + FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); } + FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); } + FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); } + FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); } + FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); } + FunctionObject *typedArrayCtors; + + Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); } + Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); } + Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); } + Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); } + Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); } + Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); } + Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); } + Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); } + Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); } + Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); } + Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); } + Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); } + Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); } + Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); } + Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); } + Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); } + Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); } + + Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); } + Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); } + Object *typedArrayPrototype; + + Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); } InternalClassPool *classPool; InternalClass *emptyClass; @@ -177,48 +232,89 @@ public: InternalClass *argumentsObjectClass; InternalClass *strictArgumentsObjectClass; - Heap::EvalFunction *evalFunction; - Heap::FunctionObject *thrower; + EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } + FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } Property *argumentsAccessors; int nArgumentsAccessors; - StringValue id_empty; - StringValue id_undefined; - StringValue id_null; - StringValue id_true; - StringValue id_false; - StringValue id_boolean; - StringValue id_number; - StringValue id_string; - StringValue id_object; - StringValue id_function; - StringValue id_length; - StringValue id_prototype; - StringValue id_constructor; - StringValue id_arguments; - StringValue id_caller; - StringValue id_callee; - StringValue id_this; - StringValue id___proto__; - StringValue id_enumerable; - StringValue id_configurable; - StringValue id_writable; - StringValue id_value; - StringValue id_get; - StringValue id_set; - StringValue id_eval; - StringValue id_uintMax; - StringValue id_name; - StringValue id_index; - StringValue id_input; - StringValue id_toString; - StringValue id_destroy; - StringValue id_valueOf; - StringValue id_byteLength; - StringValue id_byteOffset; - StringValue id_buffer; - StringValue id_lastIndex; + enum JSStrings { + String_Empty, + String_undefined, + String_null, + String_true, + String_false, + String_boolean, + String_number, + String_string, + String_object, + String_function, + String_length, + String_prototype, + String_constructor, + String_arguments, + String_caller, + String_callee, + String_this, + String___proto__, + String_enumerable, + String_configurable, + String_writable, + String_value, + String_get, + String_set, + String_eval, + String_uintMax, + String_name, + String_index, + String_input, + String_toString, + String_destroy, + String_valueOf, + String_byteLength, + String_byteOffset, + String_buffer, + String_lastIndex, + NJSStrings + }; + Value *jsStrings; + + String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); } + String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); } + String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); } + String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); } + String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); } + String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); } + String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); } + String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); } + String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); } + String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); } + String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); } + String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); } + String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); } + String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); } + String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); } + String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); } + String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); } + String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); } + String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); } + String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); } + String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); } + String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); } + String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); } + String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); } + String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); } + String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); } + String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); } + String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); } + String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); } + String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); } + String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); } + String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); } + String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); } + String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); } + String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); } + String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); } QSet<CompiledData::CompilationUnit*> compilationUnits; @@ -261,7 +357,7 @@ public: Heap::String *newString(const QString &s = QString()); Heap::String *newIdentifier(const QString &text); - Heap::Object *newStringObject(const Value &value); + Heap::Object *newStringObject(const String *string); Heap::Object *newNumberObject(double value); Heap::Object *newBooleanObject(bool b); @@ -291,7 +387,10 @@ public: Heap::Object *newForEachIteratorObject(Object *o); - Heap::Object *qmlContextObject() const; + QV4::Heap::QmlContextWrapper *qmlContextObject() const; + QObject *qmlScopeObject() const; + QQmlContextData *callingQmlContext() const; + StackTrace stackTrace(int frameLimit = -1) const; StackFrame currentStackFrame() const; @@ -305,12 +404,10 @@ public: InternalClass *newClass(const InternalClass &other); - QmlExtensions *qmlExtensions(); - bool recheckCStackLimits(); // Exception handling - Value exceptionValue; + Value *exceptionValue; StackTrace exceptionStackTrace; ReturnedValue throwError(const Value &value); @@ -335,15 +432,12 @@ public: QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true); QV4::ReturnedValue fromVariant(const QVariant &); - QVariantMap variantMapFromJS(QV4::Object *o); + QVariantMap variantMapFromJS(const QV4::Object *o); - bool metaTypeFromJS(const Value &value, int type, void *data); + bool metaTypeFromJS(const Value *value, int type, void *data); QV4::ReturnedValue metaTypeToJS(int type, const void *data); - void assertObjectBelongsToEngine(const Value &v); - -private: - QmlExtensions *m_qmlExtensions; + void assertObjectBelongsToEngine(const Heap::Base &baseObject); }; inline void ExecutionEngine::pushContext(CallContext *context) @@ -376,29 +470,26 @@ Heap::ExecutionContext::ExecutionContext(ExecutionEngine *engine, ContextType t) } -// ### Remove me inline -void Managed::mark(QV4::ExecutionEngine *engine) +void Heap::Base::mark(QV4::ExecutionEngine *engine) { Q_ASSERT(inUse()); - if (markBit()) + if (isMarked()) return; #ifndef QT_NO_DEBUG engine->assertObjectBelongsToEngine(*this); #endif - d()->setMarkBit(); - engine->pushForGC(d()); + setMarkBit(); + engine->pushForGC(this); } - -inline -void Heap::Base::mark(QV4::ExecutionEngine *engine) +inline void Value::mark(ExecutionEngine *e) { - Q_ASSERT(inUse()); - if (isMarked()) + if (!val) return; - setMarkBit(); - engine->pushForGC(this); + Managed *m = as<Managed>(); + if (m) + m->d()->mark(e); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 9034dee6a0..3c0a05483c 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -33,11 +33,14 @@ #include "qv4errorobject_p.h" -#include "qv4mm_p.h" +#include <QtCore/qnumeric.h> +#include <QtCore/qmath.h> #include <QtCore/QDateTime> #include <QtCore/QStringList> #include <QtCore/QDebug> +#include "qv4string_p.h" +#include <private/qv4mm_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> @@ -179,57 +182,57 @@ DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const Value &msg) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype.asObject(), msg, SyntaxError) + : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, SyntaxError) { } Heap::SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype.asObject(), msg, fileName, lineNumber, columnNumber, SyntaxError) + : Heap::ErrorObject(engine->emptyClass, engine->syntaxErrorPrototype(), msg, fileName, lineNumber, columnNumber, SyntaxError) { } Heap::EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype.asObject(), message, EvalError) + : Heap::ErrorObject(engine->emptyClass, engine->evalErrorPrototype(), message, EvalError) { } Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype.asObject(), message, RangeError) + : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) { } Heap::RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype.asObject(), message, RangeError) + : Heap::ErrorObject(engine->emptyClass, engine->rangeErrorPrototype(), message, RangeError) { } Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype.asObject(), message, ReferenceError) + : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) { } Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype.asObject(), message, ReferenceError) + : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), message, ReferenceError) { } Heap::ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype.asObject(), msg, fileName, lineNumber, columnNumber, ReferenceError) + : Heap::ErrorObject(engine->emptyClass, engine->referenceErrorPrototype(), msg, fileName, lineNumber, columnNumber, ReferenceError) { } Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype.asObject(), message, TypeError) + : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) { } Heap::TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message) - : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype.asObject(), message, TypeError) + : Heap::ErrorObject(engine->emptyClass, engine->typeErrorPrototype(), message, TypeError) { } Heap::URIErrorObject::URIErrorObject(ExecutionEngine *engine, const Value &message) - : Heap::ErrorObject(engine->emptyClass, engine->uRIErrorPrototype.asObject(), message, URIError) + : Heap::ErrorObject(engine->emptyClass, engine->uRIErrorPrototype(), message, URIError) { } @@ -251,16 +254,16 @@ Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name) { } -ReturnedValue ErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<ErrorCtor *>(m)->engine()); + Scope scope(static_cast<const ErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return Encode(scope.engine->newErrorObject(v)); } -ReturnedValue ErrorCtor::call(Managed *that, CallData *callData) +ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData) { - return static_cast<Object *>(that)->construct(callData); + return static_cast<const Object *>(that)->construct(callData); } Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) @@ -268,9 +271,9 @@ Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<EvalErrorCtor *>(m)->engine()); + Scope scope(static_cast<const EvalErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<EvalErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -280,9 +283,9 @@ Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<RangeErrorCtor *>(m)->engine()); + Scope scope(static_cast<const RangeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<RangeErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -292,9 +295,9 @@ Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<ReferenceErrorCtor *>(m)->engine()); + Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<ReferenceErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -304,9 +307,9 @@ Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<SyntaxErrorCtor *>(m)->engine()); + Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<SyntaxErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -316,9 +319,9 @@ Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<TypeErrorCtor *>(m)->engine()); + Scope scope(static_cast<const TypeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<TypeErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -328,9 +331,9 @@ Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData) +ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<URIErrorCtor *>(m)->engine()); + Scope scope(static_cast<const URIErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); return (scope.engine->memoryManager->alloc<URIErrorObject>(scope.engine, v))->asReturnedValue(); } @@ -340,10 +343,10 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj) Scope scope(engine); ScopedString s(scope); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = obj)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); obj->defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - obj->defineDefaultProperty(engine->id_toString, method_toString, 0); + obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); obj->defineDefaultProperty(QStringLiteral("message"), (s = engine->newString())); } @@ -351,11 +354,11 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); - ScopedValue name(scope, o->get(ctx->d()->engine->id_name)); + ScopedValue name(scope, o->get(ctx->d()->engine->id_name())); QString qname; if (name->isUndefined()) qname = QString::fromLatin1("Error"); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 071f5b8c9a..da2c978e5f 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -62,7 +62,7 @@ struct ErrorObject : Object { ErrorType errorType; StackTrace stackTrace; - String *stack; + Pointer<String> stack; }; struct EvalErrorObject : ErrorObject { @@ -141,8 +141,8 @@ struct ErrorObject: Object { }; template<> -inline ErrorObject *value_cast(const Value &v) { - return v.asErrorObject(); +inline const ErrorObject *Value::as() const { + return isManaged() && m && m->vtable->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; } struct EvalErrorObject: ErrorObject { @@ -183,50 +183,50 @@ struct ErrorCtor: FunctionObject { V4_OBJECT2(ErrorCtor, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct EvalErrorCtor: ErrorCtor { V4_OBJECT2(EvalErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct RangeErrorCtor: ErrorCtor { V4_OBJECT2(RangeErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct ReferenceErrorCtor: ErrorCtor { V4_OBJECT2(ReferenceErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct SyntaxErrorCtor: ErrorCtor { V4_OBJECT2(SyntaxErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct TypeErrorCtor: ErrorCtor { V4_OBJECT2(TypeErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; struct URIErrorCtor: ErrorCtor { V4_OBJECT2(URIErrorCtor, ErrorCtor) - static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index efe6c7c226..a18a2d4919 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -34,10 +34,10 @@ #include "qv4function_p.h" #include "qv4managed_p.h" #include "qv4string_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4engine_p.h" #include "qv4lookup_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 0a12d013ac..d8cdda477a 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4function_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" @@ -63,7 +63,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -73,7 +73,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String * } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -84,7 +84,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *fun } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -95,7 +95,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype.asObject()) + : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) , scope(scope) , function(Q_NULLPTR) { @@ -106,7 +106,7 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &nam } Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype.asObject()) + : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype()) , scope(scope->d()) , function(Q_NULLPTR) { @@ -117,7 +117,7 @@ Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const Returne } Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name) - : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype.asObject()) + : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype()) , scope(scope) , function(Q_NULLPTR) { @@ -129,7 +129,7 @@ Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValu Heap::FunctionObject::FunctionObject(InternalClass *ic, QV4::Object *prototype) : Heap::Object(ic, prototype) - , scope(ic->engine->rootContext()) + , scope(ic->engine->rootContext()->d()) , function(Q_NULLPTR) { Scope scope(ic->engine); @@ -152,7 +152,7 @@ void FunctionObject::init(String *n, bool createProto) ensureMemberIndex(s.engine, Heap::FunctionObject::Index_Prototype); if (createProto) { - ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype.asObject())); + ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); proto->ensureMemberIndex(s.engine, Heap::FunctionObject::Index_ProtoConstructor); proto->memberData()->data[Heap::FunctionObject::Index_ProtoConstructor] = this->asReturnedValue(); memberData()->data[Heap::FunctionObject::Index_Prototype] = proto.asReturnedValue(); @@ -161,12 +161,12 @@ void FunctionObject::init(String *n, bool createProto) } ScopedValue v(s, n); - defineReadonlyProperty(s.engine->id_name, v); + defineReadonlyProperty(s.engine->id_name(), v); } -ReturnedValue FunctionObject::name() +ReturnedValue FunctionObject::name() const { - return get(scope()->engine->id_name); + return get(scope()->engine->id_name()); } @@ -177,13 +177,12 @@ ReturnedValue FunctionObject::newInstance() return construct(callData); } -ReturnedValue FunctionObject::construct(Managed *that, CallData *) +ReturnedValue FunctionObject::construct(const Managed *that, CallData *) { - static_cast<FunctionObject *>(that)->internalClass()->engine->throwTypeError(); - return Encode::undefined(); + return static_cast<const FunctionObject *>(that)->engine()->throwTypeError(); } -ReturnedValue FunctionObject::call(Managed *, CallData *) +ReturnedValue FunctionObject::call(const Managed *, CallData *) { return Encode::undefined(); } @@ -237,10 +236,10 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope) } // 15.3.2 -ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) +ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) { - Scope scope(static_cast<Object *>(that)->engine()); - Scoped<FunctionCtor> f(scope, static_cast<FunctionCtor *>(that)); + Scope scope(static_cast<const Object *>(that)->engine()); + Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); ScopedContext ctx(scope, scope.engine->currentContext()); QString arguments; QString body; @@ -287,7 +286,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) } // 15.3.1: This is equivalent to new Function(...) -ReturnedValue FunctionCtor::call(Managed *that, CallData *callData) +ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } @@ -304,12 +303,12 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); - defineReadonlyProperty(engine->id_length, Primitive::fromInt32(0)); + defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("apply"), method_apply, 2); defineDefaultProperty(QStringLiteral("call"), method_call, 1); defineDefaultProperty(QStringLiteral("bind"), method_bind, 1); @@ -318,7 +317,7 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) { - FunctionObject *fun = ctx->thisObject().asFunctionObject(); + FunctionObject *fun = ctx->thisObject().as<FunctionObject>(); if (!fun) return ctx->engine()->throwTypeError(); @@ -328,7 +327,7 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) { Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().asFunctionObject()); + ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); if (!o) return ctx->engine()->throwTypeError(); @@ -370,7 +369,7 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) { Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().asFunctionObject()); + ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); if (!o) return ctx->engine()->throwTypeError(); @@ -409,15 +408,15 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun { } -ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) +ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that)); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); @@ -441,15 +440,15 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) return obj.asReturnedValue(); } -ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) +ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that)); + Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); ScopedContext context(scope, v4->currentContext()); Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); @@ -458,7 +457,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); if (f->function()->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(ctx->d()->engine, f->function()->compiledFunction); + QmlContextWrapper::registerQmlDependencies(scope.engine, f->function()->compiledFunction); return result->asReturnedValue(); } @@ -466,7 +465,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) DEFINE_OBJECT_VTABLE(SimpleScriptFunction); Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto) - : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype.asObject()) + : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype()) { this->scope = scope->d(); @@ -481,7 +480,7 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F if (createProto) { ScopedString name(s, function->name()); f->init(name, createProto); - f->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(f->formalParameterCount())); + f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount())); } else { f->ensureMemberIndex(s.engine, Index_Length); memberData->data[Index_Name] = function->name(); @@ -490,22 +489,22 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F if (scope->d()->strictMode) { ScopedProperty pd(s); - pd->value = s.engine->thrower; - pd->set = s.engine->thrower; - f->insertMember(scope->d()->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(scope->d()->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + pd->value = s.engine->thrower(); + pd->set = s.engine->thrower(); + f->insertMember(scope->d()->engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(scope->d()->engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } } -ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) +ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(that)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); InternalClass *ic = scope.engine->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); @@ -536,15 +535,15 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) return result.asReturnedValue(); } -ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) +ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData) { - ExecutionEngine *v4 = static_cast<SimpleScriptFunction *>(that)->internalClass()->engine; + ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); Scope scope(v4); - Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that)); + Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); ExecutionContextSaver ctxSaver(scope, v4->currentContext()); @@ -575,7 +574,7 @@ Heap::Object *SimpleScriptFunction::protoForConstructor() ScopedObject p(scope, protoProperty()); if (p) return p->d(); - return scope.engine->objectPrototype.asObject()->d(); + return scope.engine->objectPrototype()->d(); } @@ -588,14 +587,14 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String { } -ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) +ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *) { - return static_cast<BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) +ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) { - BuiltinFunction *f = static_cast<BuiltinFunction *>(that); + const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); @@ -614,9 +613,9 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) return f->d()->code(sctx); } -ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) +ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) { - IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that); + const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); @@ -650,24 +649,24 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb Scope s(scope); ScopedObject f(s, this); - ScopedValue l(s, target->get(s.engine->id_length)); + ScopedValue l(s, target->get(s.engine->id_length())); int len = l->toUInt32(); if (boundArgs) len -= boundArgs->size(); if (len < 0) len = 0; - f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(len)); + f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len)); ScopedProperty pd(s); - pd->value = s.engine->thrower; - pd->set = s.engine->thrower; - f->insertMember(s.engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(s.engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + pd->value = s.engine->thrower(); + pd->set = s.engine->thrower(); + f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } -ReturnedValue BoundFunction::call(Managed *that, CallData *dd) +ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) { - BoundFunction *f = static_cast<BoundFunction *>(that); + const BoundFunction *f = static_cast<const BoundFunction *>(that); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); @@ -685,9 +684,9 @@ ReturnedValue BoundFunction::call(Managed *that, CallData *dd) return t->call(callData); } -ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) +ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) { - BoundFunction *f = static_cast<BoundFunction *>(that); + const BoundFunction *f = static_cast<const BoundFunction *>(that); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 252ff40a1a..930b65156f 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -36,7 +36,7 @@ #include "qv4object_p.h" #include "qv4function_p.h" #include "qv4context_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE @@ -65,7 +65,7 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } - ExecutionContext *scope; + Pointer<ExecutionContext> scope; Function *function; }; @@ -102,9 +102,9 @@ struct ScriptFunction : SimpleScriptFunction { struct BoundFunction : FunctionObject { BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); - FunctionObject *target; + Pointer<FunctionObject> target; Value boundThis; - MemberData *boundArgs; + Pointer<MemberData> boundArgs; }; } @@ -117,12 +117,12 @@ struct Q_QML_EXPORT FunctionObject: Object { Q_MANAGED_TYPE(FunctionObject) V4_NEEDS_DESTROY - Heap::ExecutionContext *scope() { return d()->scope; } - Function *function() { return d()->function; } + Heap::ExecutionContext *scope() const { return d()->scope; } + Function *function() const { return d()->function; } - ReturnedValue name(); - unsigned int formalParameterCount() { return d()->formalParameterCount(); } - unsigned int varCount() { return d()->varCount(); } + ReturnedValue name() const; + unsigned int formalParameterCount() const { return d()->formalParameterCount(); } + unsigned int varCount() const { return d()->varCount(); } void init(String *name, bool createProto); @@ -130,12 +130,8 @@ struct Q_QML_EXPORT FunctionObject: Object { using Object::construct; using Object::call; - static ReturnedValue construct(Managed *that, CallData *); - static ReturnedValue call(Managed *that, CallData *d); - - static FunctionObject *cast(const Value &v) { - return v.asFunctionObject(); - } + static ReturnedValue construct(const Managed *that, CallData *); + static ReturnedValue call(const Managed *that, CallData *d); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); @@ -152,16 +148,17 @@ struct Q_QML_EXPORT FunctionObject: Object { }; template<> -inline FunctionObject *value_cast(const Value &v) { - return v.asFunctionObject(); +inline const FunctionObject *Value::as() const { + return isManaged() && m && m->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; } + struct FunctionCtor: FunctionObject { V4_OBJECT2(FunctionCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct FunctionPrototype: FunctionObject @@ -184,20 +181,20 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); } - static ReturnedValue construct(Managed *, CallData *); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct IndexedBuiltinFunction: FunctionObject { V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *) + static ReturnedValue construct(const Managed *m, CallData *) { - return static_cast<IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); + return static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); } - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index, @@ -212,8 +209,8 @@ Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scop struct SimpleScriptFunction: FunctionObject { V4_OBJECT2(SimpleScriptFunction, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); Heap::Object *protoForConstructor(); }; @@ -221,8 +218,8 @@ struct SimpleScriptFunction: FunctionObject { struct ScriptFunction: SimpleScriptFunction { V4_OBJECT2(ScriptFunction, FunctionObject) - static ReturnedValue construct(Managed *, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; @@ -234,12 +231,12 @@ struct BoundFunction: FunctionObject { return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); } - Heap::FunctionObject *target() { return d()->target; } + Heap::FunctionObject *target() const { return d()->target; } Value boundThis() const { return d()->boundThis; } Heap::MemberData *boundArgs() const { return d()->boundArgs; } - static ReturnedValue construct(Managed *, CallData *d); - static ReturnedValue call(Managed *that, CallData *dd); + static ReturnedValue construct(const Managed *, CallData *d); + static ReturnedValue call(const Managed *that, CallData *dd); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 4b08194b60..6d7135cbaa 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -88,6 +88,8 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #define V4_ENABLE_JIT #endif +#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) +#define V4_ENABLE_JIT #endif // Black list some platforms @@ -168,7 +170,7 @@ struct Property; struct Value; struct Lookup; struct ArrayData; -struct ManagedVTable; +struct VTable; struct BooleanObject; struct NumberObject; @@ -211,7 +213,6 @@ class WeakValue; struct IdentifierTable; class RegExpCache; class MultiplyWrappedQObjectMap; -struct QmlExtensions; namespace Global { enum { diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 8e33cec57f..3b1f09e502 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -32,13 +32,14 @@ ****************************************************************************/ #include "qv4globalobject_p.h" -#include "qv4mm_p.h" -#include "qv4value_inl_p.h" +#include <private/qv4mm_p.h> +#include "qv4value_p.h" #include "qv4context_p.h" #include "qv4function_p.h" #include "qv4debugging_p.h" #include "qv4script_p.h" #include "qv4scopedvalue_p.h" +#include "qv4string_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -339,14 +340,14 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) DEFINE_OBJECT_VTABLE(EvalFunction); Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval()) { Scope s(scope); ScopedFunctionObject f(s, this); - f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(1)); + f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1)); } -ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) +ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const { if (callData->argc < 1) return Encode::undefined(); @@ -399,10 +400,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) } -ReturnedValue EvalFunction::call(Managed *that, CallData *callData) +ReturnedValue EvalFunction::call(const Managed *that, CallData *callData) { // indirect call - return static_cast<EvalFunction *>(that)->evalCall(callData, false); + return static_cast<const EvalFunction *>(that)->evalCall(callData, false); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index 74de233b47..ba1d5d2e0b 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -52,10 +52,10 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject { V4_OBJECT2(EvalFunction, FunctionObject) - ReturnedValue evalCall(CallData *callData, bool directCall); + ReturnedValue evalCall(CallData *callData, bool directCall) const; using Object::construct; - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct GlobalFunctions diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index e4bd460966..2eb61081c7 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -54,7 +54,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QQmlContex : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context) { m_qmlglobal.set(engine, qmlglobal); - if (callback.asFunctionObject()) + if (callback.as<QV4::FunctionObject>()) m_callbackFunction.set(engine, callback); m_resultObject.set(v4, resultValue(v4)); @@ -94,14 +94,14 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status) { if (!callback.isObject()) return; - QV4::ExecutionEngine *v4 = callback.asObject()->engine(); + QV4::ExecutionEngine *v4 = callback.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedFunctionObject f(scope, callback); if (!f) return; QV4::ScopedCallData callData(scope, 1); - callData->thisObject = v4->globalObject()->asReturnedValue(); + callData->thisObject = v4->globalObject->asReturnedValue(); callData->args[0] = status; f->call(callData); if (scope.hasException()) @@ -176,7 +176,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) return QV4::Encode::undefined(); QV4::Scope scope(ctx->engine()); - QQmlContextData *context = QV4::QmlContextWrapper::callingContext(scope.engine); + QQmlContextData *context = scope.engine->callingQmlContext(); if (!context || !context->isJSContext) V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files"); @@ -184,7 +184,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); - if (ctx->argc() >= 2 && ctx->args()[1].asFunctionObject()) + if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>()) callbackFunction = ctx->args()[1]; QString localFile = QQmlFile::urlToLocalFileOrQrc(url); @@ -224,7 +224,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QV4::ScopedValue ex(scope, scope.engine->catchException()); result = resultValue(scope.engine, Exception); QV4::ScopedString exception(scope, scope.engine->newString(QStringLiteral("exception"))); - result->asObject()->put(exception, ex); + result->as<QV4::Object>()->put(exception, ex); } else { result = resultValue(scope.engine, Ok); } diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 5dc94e8555..5ef4442b03 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -50,7 +50,7 @@ #include <private/qqmlcontext_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4context_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 3289058cb7..80590fe72e 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -46,7 +46,7 @@ struct String; struct ExecutionEngine; struct Object; struct Identifier; -struct ManagedVTable; +struct VTable; struct PropertyHashData; struct PropertyHash diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index e7905974df..d634e783bd 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -38,8 +38,8 @@ #include <qv4objectiterator_p.h> #include <qv4scopedvalue_p.h> #include <qv4runtime_p.h> +#include "qv4string_p.h" -#include <qjsondocument.h> #include <qstack.h> #include <qstringlist.h> @@ -62,33 +62,6 @@ static int indent = 0; DEFINE_OBJECT_VTABLE(JsonObject); -class JsonParser -{ -public: - JsonParser(ExecutionEngine *engine, const QChar *json, int length); - - ReturnedValue parse(QJsonParseError *error); - -private: - inline bool eatSpace(); - inline QChar nextToken(); - - ReturnedValue parseObject(); - ReturnedValue parseArray(); - bool parseMember(Object *o); - bool parseString(QString *string); - bool parseValue(Value *val); - bool parseNumber(Value *val); - - ExecutionEngine *engine; - const QChar *head; - const QChar *json; - const QChar *end; - - int nestingLevel; - QJsonParseError::ParseError lastError; -}; - static const int nestingLimit = 1024; @@ -639,17 +612,22 @@ bool JsonParser::parseString(QString *string) struct Stringify { - ExecutionContext *ctx; + ExecutionEngine *v4; FunctionObject *replacerFunction; - // ### GC - QVector<Heap::String *> propertyList; + QV4::String *propertyList; + int propertyListSize; QString gap; QString indent; + QStack<Object *> stack; - // ### GC - QStack<Heap::Object *> stack; + bool stackContains(Object *o) { + for (int i = 0; i < stack.size(); ++i) + if (stack.at(i)->d() == o->d()) + return true; + return false; + } - Stringify(ExecutionContext *ctx) : ctx(ctx), replacerFunction(0) {} + Stringify(ExecutionEngine *e) : v4(e), replacerFunction(0), propertyList(0), propertyListSize(0) {} QString Str(const QString &key, const Value &v); QString JA(ArrayObject *a); @@ -701,26 +679,26 @@ static QString quote(const QString &str) QString Stringify::Str(const QString &key, const Value &v) { - Scope scope(ctx); + Scope scope(v4); ScopedValue value(scope, v); ScopedObject o(scope, value); if (o) { - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toJSON"))); + ScopedString s(scope, v4->newString(QStringLiteral("toJSON"))); ScopedFunctionObject toJSON(scope, o->get(s)); if (!!toJSON) { ScopedCallData callData(scope, 1); callData->thisObject = value; - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = v4->newString(key); value = toJSON->call(callData); } } if (replacerFunction) { - ScopedObject holder(scope, ctx->d()->engine->newObject()); + ScopedObject holder(scope, v4->newObject()); holder->put(scope.engine, QString(), value); ScopedCallData callData(scope, 2); - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = v4->newString(key); callData->args[1] = value; callData->thisObject = holder; value = replacerFunction->call(callData); @@ -728,11 +706,11 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { - if (NumberObject *n = o->asNumberObject()) + if (NumberObject *n = o->as<NumberObject>()) value = Encode(n->value()); - else if (StringObject *so = o->asStringObject()) - value = so->d()->value; - else if (BooleanObject *b =o->asBooleanObject()) + else if (StringObject *so = o->as<StringObject>()) + value = so->d()->string; + else if (BooleanObject *b = o->as<BooleanObject>()) value = Encode(b->value()); } @@ -750,8 +728,8 @@ QString Stringify::Str(const QString &key, const Value &v) o = value->asReturnedValue(); if (o) { - if (!o->asFunctionObject()) { - if (o->asArrayObject()) { + if (!o->as<FunctionObject>()) { + if (o->as<ArrayObject>()) { return JA(static_cast<ArrayObject *>(o.getPointer())); } else { return JO(o); @@ -777,20 +755,20 @@ QString Stringify::makeMember(const QString &key, const Value &v) QString Stringify::JO(Object *o) { - if (stack.contains(o->d())) { - ctx->engine()->throwTypeError(); + if (stackContains(o)) { + v4->throwTypeError(); return QString(); } - Scope scope(ctx); + Scope scope(v4); QString result; - stack.push(o->d()); + stack.push(o); QString stepback = indent; indent += gap; QStringList partial; - if (propertyList.isEmpty()) { + if (!propertyListSize) { ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -805,11 +783,13 @@ QString Stringify::JO(Object *o) partial += member; } } else { - ScopedString s(scope); - for (int i = 0; i < propertyList.size(); ++i) { + ScopedValue v(scope); + for (int i = 0; i < propertyListSize; ++i) { bool exists; - s = propertyList.at(i); - ScopedValue v(scope, o->get(s, &exists)); + String *s = propertyList + i; + if (!s) + continue; + v = o->get(s, &exists); if (!exists) continue; QString member = makeMember(s->toQString(), v); @@ -834,15 +814,15 @@ QString Stringify::JO(Object *o) QString Stringify::JA(ArrayObject *a) { - if (stack.contains(a->d())) { - ctx->engine()->throwTypeError(); + if (stackContains(a)) { + v4->throwTypeError(); return QString(); } Scope scope(a->engine()); QString result; - stack.push(a->d()); + stack.push(a); QString stepback = indent; indent += gap; @@ -879,7 +859,7 @@ QString Stringify::JA(ArrayObject *a) Heap::JsonObject::JsonObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype.asObject()) + : Heap::Object(e->emptyClass, e->objectPrototype()) { Scope scope(e); ScopedObject o(scope, this); @@ -911,32 +891,38 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) { Scope scope(ctx); - Stringify stringify(ctx); + Stringify stringify(scope.engine); ScopedObject o(scope, ctx->argument(1)); if (o) { - stringify.replacerFunction = o->asFunctionObject(); + stringify.replacerFunction = o->as<FunctionObject>(); if (o->isArrayObject()) { uint arrayLen = o->getLength(); - ScopedValue v(scope); + stringify.propertyList = static_cast<QV4::String *>(scope.alloc(arrayLen)); for (uint i = 0; i < arrayLen; ++i) { - v = o->getIndexed(i); - if (v->asNumberObject() || v->asStringObject() || v->isNumber()) - v = RuntimeHelpers::toString(scope.engine, v); - if (v->isString()) { - String *s = v->stringValue(); - if (!stringify.propertyList.contains(s->d())) - stringify.propertyList.append(s->d()); + Value *v = stringify.propertyList + i; + *v = o->getIndexed(i); + if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber()) + *v = RuntimeHelpers::toString(scope.engine, *v); + if (!v->isString()) { + v->m = 0; + } else { + for (uint j = 0; j <i; ++j) { + if (stringify.propertyList[j].m == v->m) { + v->m = 0; + break; + } + } } } } } ScopedValue s(scope, ctx->argument(2)); - if (NumberObject *n = s->asNumberObject()) + if (NumberObject *n = s->as<NumberObject>()) s = Encode(n->value()); - else if (StringObject *so = s->asStringObject()) - s = so->d()->value; + else if (StringObject *so = s->as<StringObject>()) + s = so->d()->string; if (s->isNumber()) { stringify.gap = QString(qMin(10, (int)s->toInteger()), ' '); @@ -986,7 +972,7 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec return QJsonValue(value.toQString()); Q_ASSERT(value.isObject()); - Scope scope(value.asObject()->engine()); + Scope scope(value.as<Object>()->engine()); ScopedArrayObject a(scope, value); if (a) return toJsonArray(a, visitedObjects); @@ -1009,22 +995,22 @@ QV4::ReturnedValue JsonObject::fromJsonObject(ExecutionEngine *engine, const QJs return o.asReturnedValue(); } -QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) +QJsonObject JsonObject::toJsonObject(const Object *o, V4ObjectSet &visitedObjects) { QJsonObject result; - if (!o || o->asFunctionObject()) + if (!o || o->as<FunctionObject>()) return result; Scope scope(o->engine()); - if (visitedObjects.contains(o->d())) { + if (visitedObjects.contains(ObjectItem(o))) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). return result; } - visitedObjects.insert(o->d()); + visitedObjects.insert(ObjectItem(o)); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -1035,11 +1021,11 @@ QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) break; QString key = name->toQStringNoThrow(); - if (!val->asFunctionObject()) + if (!val->as<FunctionObject>()) result.insert(key, toJsonValue(val, visitedObjects)); } - visitedObjects.remove(o->d()); + visitedObjects.remove(ObjectItem(o)); return result; } @@ -1057,7 +1043,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso return a.asReturnedValue(); } -QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) +QJsonArray JsonObject::toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects) { QJsonArray result; if (!a) @@ -1065,25 +1051,25 @@ QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) Scope scope(a->engine()); - if (visitedObjects.contains(a->d())) { + if (visitedObjects.contains(ObjectItem(a))) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty array (and no error is thrown). return result; } - visitedObjects.insert(a->d()); + visitedObjects.insert(ObjectItem(a)); ScopedValue v(scope); quint32 length = a->getLength(); for (quint32 i = 0; i < length; ++i) { v = a->getIndexed(i); - if (v->asFunctionObject()) + if (v->as<FunctionObject>()) v = Encode::null(); result.append(toJsonValue(v, visitedObjects)); } - visitedObjects.remove(a->d()); + visitedObjects.remove(ObjectItem(a)); return result; } diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 81a783ee92..1ad0e2c5de 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -37,6 +37,8 @@ #include <qjsonarray.h> #include <qjsonobject.h> #include <qjsonvalue.h> +#include <qjsondocument.h> +#include <qhash.h> QT_BEGIN_NAMESPACE @@ -50,12 +52,23 @@ struct JsonObject : Object { } +struct ObjectItem { + const QV4::Object *o; + ObjectItem(const QV4::Object *o) : o(o) {} +}; + +inline bool operator ==(const ObjectItem &a, const ObjectItem &b) +{ return a.o->d() == b.o->d(); } + +inline int qHash(const ObjectItem &i, uint seed = 0) +{ return ::qHash((void *)i.o->d(), seed); } + struct JsonObject : Object { Q_MANAGED_TYPE(JsonObject) V4_OBJECT2(JsonObject, Object) private: - // ### GC - typedef QSet<QV4::Heap::Base *> V4ObjectSet; + + typedef QSet<ObjectItem> V4ObjectSet; public: static ReturnedValue method_parse(CallContext *ctx); @@ -67,18 +80,45 @@ public: static inline QJsonValue toJsonValue(const QV4::Value &value) { V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); } - static inline QJsonObject toJsonObject(QV4::Object *o) + static inline QJsonObject toJsonObject(const QV4::Object *o) { V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); } - static inline QJsonArray toJsonArray(QV4::ArrayObject *a) + static inline QJsonArray toJsonArray(const QV4::ArrayObject *a) { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); } private: static QJsonValue toJsonValue(const QV4::Value &value, V4ObjectSet &visitedObjects); - static QJsonObject toJsonObject(Object *o, V4ObjectSet &visitedObjects); - static QJsonArray toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects); + static QJsonObject toJsonObject(const Object *o, V4ObjectSet &visitedObjects); + static QJsonArray toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects); }; +class JsonParser +{ +public: + JsonParser(ExecutionEngine *engine, const QChar *json, int length); + + ReturnedValue parse(QJsonParseError *error); + +private: + inline bool eatSpace(); + inline QChar nextToken(); + + ReturnedValue parseObject(); + ReturnedValue parseArray(); + bool parseMember(Object *o); + bool parseString(QString *string); + bool parseValue(Value *val); + bool parseNumber(Value *val); + + ExecutionEngine *engine; + const QChar *head; + const QChar *json; + const QChar *end; + + int nestingLevel; + QJsonParseError::ParseError lastError; +}; + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 82b20337cb..443427b024 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -33,6 +33,7 @@ #include "qv4lookup_p.h" #include "qv4functionobject_p.h" #include "qv4scopedvalue_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -72,7 +73,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return Primitive::emptyValue().asReturnedValue(); } -ReturnedValue Lookup::lookup(Object *thisObject, PropertyAttributes *attrs) +ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs) { Heap::Object *obj = thisObject->d(); ExecutionEngine *engine = thisObject->engine(); @@ -123,7 +124,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons ScopedObject o(scope, object); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); } @@ -168,7 +169,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) if (!s->data(idx).isEmpty()) return s->data(idx).asReturnedValue(); @@ -200,7 +201,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & uint idx = index.asArrayIndex(); if (idx < UINT_MAX) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { s->data(idx) = value; return; @@ -224,7 +225,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value Object *o = object.objectValue(); if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { s->data(idx) = v; return; @@ -235,7 +236,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (Object *o = object.asObject()) + if (const Object *o = object.as<Object>()) return o->getLookup(l); Object *proto; @@ -244,14 +245,14 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va case Value::Null_Type: return engine->throwTypeError(); case Value::Boolean_Type: - proto = engine->booleanPrototype.asObject(); + proto = engine->booleanPrototype(); break; case Value::Managed_Type: { Q_ASSERT(object.isString()); - proto = engine->stringPrototype.asObject(); + proto = engine->stringPrototype(); Scope scope(engine); ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (name->equals(engine->id_length)) { + if (name->equals(engine->id_length())) { // special case, as the property is on the object itself l->getter = stringLengthGetter; return stringLengthGetter(l, engine, object); @@ -260,7 +261,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va } case Value::Integer_Type: default: // Number - proto = engine->numberPrototype.asObject(); + proto = engine->numberPrototype(); } PropertyAttributes attrs; @@ -291,7 +292,7 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Lookup l1 = *l; if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) { - if (Object *o = object.asObject()) { + if (const Object *o = object.as<Object>()) { ReturnedValue v = o->getLookup(l); Lookup l2 = *l; @@ -560,7 +561,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (String *s = object.asString()) + if (const String *s = object.as<String>()) return Encode(s->d()->length()); l->getter = getterGeneric; @@ -569,7 +570,7 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, con ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (ArrayObject *a = object.asArrayObject()) + if (const ArrayObject *a = object.as<ArrayObject>()) return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); l->getter = getterGeneric; @@ -579,7 +580,7 @@ ReturnedValue Lookup::arrayLengthGetter(Lookup *l, ExecutionEngine *engine, cons ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -608,7 +609,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) return o->memberData()->data[l->index].asReturnedValue(); @@ -618,7 +619,7 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) return o->prototype()->memberData->data[l->index].asReturnedValue(); @@ -629,7 +630,7 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) { - Heap::Object *o = engine->globalObject()->d(); + Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { @@ -645,7 +646,7 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); ScopedFunctionObject getter(scope, o->propertyAt(l->index)->getter()); @@ -662,7 +663,7 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) { - Object *o = engine->globalObject(); + Object *o = engine->globalObject; if (l->classList[0] == o->internalClass() && l->classList[1] == o->prototype()->internalClass) { Scope scope(o->engine()); @@ -680,7 +681,7 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) { - Heap::Object *o = engine->globalObject()->d(); + Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { @@ -701,7 +702,7 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) return globalGetterGeneric(l, engine); } -void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Scope scope(engine); ScopedObject o(scope, object); @@ -716,11 +717,11 @@ void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &obje o->setLookup(l, value); } -void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Lookup l1 = *l; - if (Object *o = object.asObject()) { + if (Object *o = object.as<Object>()) { o->setLookup(l, value); if (l->setter == Lookup::setter0) { @@ -735,7 +736,7 @@ void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &o setterFallback(l, engine, object, value); } -void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { QV4::Scope scope(engine); QV4::ScopedObject o(scope, object.toObject(scope.engine)); @@ -745,9 +746,9 @@ void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, const Value &obj } } -void Lookup::setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { o->memberData()->data[l->index] = value; return; @@ -756,9 +757,9 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, const Value &object, co setterTwoClasses(l, engine, object, value); } -void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { if (!o->memberData() || l->index >= o->memberData()->size) @@ -773,9 +774,9 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { @@ -791,9 +792,9 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { @@ -812,9 +813,9 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &obje setterFallback(l, engine, object, value); } -void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value) +void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = static_cast<Object *>(object.asManaged()); + Object *o = object.as<Object>(); if (o) { if (o->internalClass() == l->classList[0]) { o->memberData()->data[l->index] = value; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 88397dc36c..232e909c48 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -51,7 +51,7 @@ struct Lookup { void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v); ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); - void (*setter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &v); + void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; union { ExecutionEngine *engine; @@ -107,17 +107,17 @@ struct Lookup { static ReturnedValue globalGetterAccessor1(Lookup *l, ExecutionEngine *engine); static ReturnedValue globalGetterAccessor2(Lookup *l, ExecutionEngine *engine); - static void setterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert1(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setterInsert2(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); - static void setter0setter0(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &value); + static void setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); ReturnedValue lookup(const Value &thisObject, Object *obj, PropertyAttributes *attrs); - ReturnedValue lookup(Object *obj, PropertyAttributes *attrs); + ReturnedValue lookup(const Object *obj, PropertyAttributes *attrs); }; diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index c4b9fc597e..546190086e 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -32,13 +32,13 @@ ****************************************************************************/ #include "qv4managed_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4errorobject_p.h" using namespace QV4; -const ManagedVTable Managed::static_vtbl = +const VTable Managed::static_vtbl = { 0, Managed::IsExecutionContext, diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 0fe5c7ee49..7cce80d087 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -35,7 +35,7 @@ #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4internalclass_p.h" +#include <private/qv4heap_p.h> QT_BEGIN_NAMESPACE @@ -65,8 +65,8 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} Q_MANAGED_CHECK \ typedef QV4::Heap::DataClass Data; \ typedef superClass SuperClass; \ - static const QV4::ManagedVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \ + static const QV4::VTable static_vtbl; \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl; } \ V4_MANAGED_SIZE_TEST \ QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m); } @@ -86,23 +86,6 @@ struct GCDeletable bool lastCall; }; -struct ManagedVTable -{ - const ManagedVTable * const parent; - uint isExecutionContext : 1; - uint isString : 1; - uint isObject : 1; - uint isFunctionObject : 1; - uint isErrorObject : 1; - uint isArrayData : 1; - uint unused : 18; - uint type : 8; - const char *className; - void (*destroy)(Heap::Base *); - void (*markObjects)(Heap::Base *, ExecutionEngine *e); - bool (*isEqualTo)(Managed *m, Managed *other); -}; - #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ parentVTable, \ @@ -121,7 +104,7 @@ struct ManagedVTable } #define DEFINE_MANAGED_VTABLE(classname) \ -const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) +const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) struct Q_QML_PRIVATE_EXPORT Managed : Value { @@ -141,8 +124,6 @@ private: public: - inline void mark(QV4::ExecutionEngine *engine); - enum Type { Type_Invalid, Type_String, @@ -167,46 +148,6 @@ public: }; Q_MANAGED_TYPE(Invalid) - template <typename T> - T *as() { - Q_ASSERT(d()->vtable); -#if !defined(QT_NO_QOBJECT_CHECK) - static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(this)); -#endif - const ManagedVTable *vt = d()->vtable; - while (vt) { - if (vt == T::staticVTable()) - return static_cast<T *>(this); - vt = vt->parent; - } - return 0; - } - template <typename T> - const T *as() const { - Q_ASSERT(d()->vtable); -#if !defined(QT_NO_QOBJECT_CHECK) - static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(const_cast<Managed *>(this))); -#endif - const ManagedVTable *vt = d()->vtable; - while (vt) { - if (vt == T::staticVTable()) - return static_cast<T *>(this); - vt = vt->parent; - } - return 0; - } - - String *asString() { return d()->vtable->isString ? reinterpret_cast<String *>(this) : 0; } - Object *asObject() { return d()->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; } - ArrayObject *asArrayObject() { return d()->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; } - FunctionObject *asFunctionObject() { return d()->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; } - BooleanObject *asBooleanObject() { return d()->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; } - NumberObject *asNumberObject() { return d()->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; } - StringObject *asStringObject() { return d()->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; } - DateObject *asDateObject() { return d()->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; } - ErrorObject *asErrorObject() { return d()->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; } - ArgumentsObject *asArgumentsObject() { return d()->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; } - bool isListType() const { return d()->vtable->type == Type_QmlSequence; } bool isArrayObject() const { return d()->vtable->type == Type_ArrayObject; } @@ -231,37 +172,15 @@ private: template<> -inline Managed *value_cast(const Value &v) { - return v.asManaged(); -} - -template<typename T> -inline T *managed_cast(Managed *m) -{ - return m ? m->as<T>() : 0; +inline const Managed *Value::as() const { + if (isManaged()) + return managed(); + return 0; } template<> -inline String *managed_cast(Managed *m) -{ - return m ? m->asString() : 0; -} -template<> -inline Object *managed_cast(Managed *m) -{ - return m ? m->asObject() : 0; -} -template<> -inline FunctionObject *managed_cast(Managed *m) -{ - return m ? m->asFunctionObject() : 0; -} - -inline Value Value::fromManaged(Managed *m) -{ - if (!m) - return QV4::Primitive::undefinedValue(); - return *m; +inline const Object *Value::as() const { + return isManaged() && m && m->vtable->isObject ? objectValue() : 0; } } diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 473e05bf88..c498160c36 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -48,7 +48,7 @@ DEFINE_OBJECT_VTABLE(MathObject); static const double qt_PI = 2.0 * ::asin(1.0); Heap::MathObject::MathObject(ExecutionEngine *e) - : Heap::Object(e->emptyClass, e->objectPrototype.asObject()) + : Heap::Object(e->emptyClass, e->objectPrototype()) { Scope scope(e); ScopedObject m(scope, this); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 03dfee3dcf..5ec5cb1f58 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -32,7 +32,8 @@ ****************************************************************************/ #include "qv4memberdata_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> +#include "qv4value_p.h" using namespace QV4; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 89ff110b20..36b83090e1 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -33,6 +33,7 @@ #include "qv4numberobject_p.h" #include "qv4runtime_p.h" +#include "qv4string_p.h" #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> @@ -50,14 +51,14 @@ Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope) { } -ReturnedValue NumberCtor::construct(Managed *m, CallData *callData) +ReturnedValue NumberCtor::construct(const Managed *m, CallData *callData) { Scope scope(m->cast<NumberCtor>()->engine()); double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Encode(scope.engine->newNumberObject(dbl)); } -ReturnedValue NumberCtor::call(Managed *, CallData *callData) +ReturnedValue NumberCtor::call(const Managed *, CallData *callData) { double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Encode(dbl); @@ -67,8 +68,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(qSNaN())); ctor->defineReadonlyProperty(QStringLiteral("NEGATIVE_INFINITY"), Primitive::fromDouble(-qInf())); @@ -85,9 +86,9 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) #endif defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); + defineDefaultProperty(engine->id_toString(), method_toString); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - defineDefaultProperty(engine->id_valueOf, method_valueOf); + defineDefaultProperty(engine->id_valueOf(), method_valueOf); defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1); defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential); defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision); @@ -97,7 +98,7 @@ inline ReturnedValue thisNumberValue(ExecutionContext *ctx) { if (ctx->thisObject().isNumber()) return ctx->thisObject().asReturnedValue(); - NumberObject *n = ctx->thisObject().asNumberObject(); + NumberObject *n = ctx->thisObject().as<NumberObject>(); if (!n) return ctx->engine()->throwTypeError(); return Encode(n->value()); @@ -107,7 +108,7 @@ inline double thisNumber(ExecutionContext *ctx) { if (ctx->thisObject().isNumber()) return ctx->thisObject().asDouble(); - NumberObject *n = ctx->thisObject().asNumberObject(); + NumberObject *n = ctx->thisObject().as<NumberObject>(); if (!n) return ctx->engine()->throwTypeError(); return n->value(); diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 205995701b..04798d31fc 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -53,8 +53,8 @@ struct NumberCtor: FunctionObject { V4_OBJECT2(NumberCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *, CallData *callData); }; struct NumberPrototype: NumberObject diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 211fd1812e..b4ad477e89 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -37,12 +37,13 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" #include "qv4memberdata_p.h" #include "qv4objectiterator_p.h" #include "qv4identifier_p.h" +#include "qv4string_p.h" #include <stdint.h> @@ -138,7 +139,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca ScopedString s(scope, e->newIdentifier(name)); ScopedContext global(scope, e->rootContext()); ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); - function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); } @@ -148,7 +149,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte Scope scope(e); ScopedContext global(scope, e->rootContext()); ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); - function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } @@ -219,50 +220,50 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri } // Section 8.12.1 -Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs) +void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) - return __getOwnProperty__(idx, attrs); + return getOwnProperty(idx, attrs, p); uint member = internalClass()->find(name); if (member < UINT_MAX) { - if (attrs) - *attrs = internalClass()->propertyData[member]; - return propertyAt(member); + *attrs = internalClass()->propertyData[member]; + if (p) + p->copy(propertyAt(member), *attrs); + return; } if (attrs) *attrs = Attr_Invalid; - return 0; + return; } -Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs) +void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) { - Property *p = arrayData() ? arrayData()->getProperty(index) : 0; - if (p) { - if (attrs) - *attrs = arrayData()->attributes(index); - return p; + Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; + if (pd) { + *attrs = arrayData()->attributes(index); + if (p) + p->copy(pd, *attrs); + return; } if (isStringObject()) { - if (attrs) - *attrs = Attr_NotConfigurable|Attr_NotWritable; - return static_cast<StringObject *>(this)->getIndex(index); + *attrs = Attr_NotConfigurable|Attr_NotWritable; + if (p) + p->value = static_cast<StringObject *>(this)->getIndex(index); + return; } if (attrs) *attrs = Attr_Invalid; - return 0; + return; } // Section 8.12.2 Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const { - uint idx = name->asArrayIndex(); - if (idx != UINT_MAX) - return __getPropertyDescriptor__(idx, attrs); - + Q_ASSERT(name->asArrayIndex() == UINT_MAX); const Heap::Object *o = d(); while (o) { @@ -286,16 +287,15 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr while (o) { Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0; if (p) { - if (attrs) - *attrs = o->arrayData->attributes(index); + *attrs = o->arrayData->attributes(index); return p; } if (o->vtable->type == Type_StringObject) { - Property *p = static_cast<const Heap::StringObject *>(o)->getIndex(index); - if (p) { - if (attrs) - *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return p; + if (index < static_cast<const Heap::StringObject *>(o)->length()) { + // this is an evil hack, but it works, as the method is only ever called from putIndexed, + // where we don't use the returned pointer there for non writable attributes + *attrs = (Attr_NotWritable|Attr_NotConfigurable); + return reinterpret_cast<Property *>(0x1); } } o = o->prototype; @@ -356,8 +356,7 @@ bool Object::hasOwnProperty(uint index) const return true; if (isStringObject()) { - String *s = static_cast<const StringObject *>(this)->d()->value.asString(); - if (index < (uint)s->d()->length()) + if (index < static_cast<const StringObject *>(this)->length()) return true; } if (!queryIndexed(index).isEmpty()) @@ -365,24 +364,24 @@ bool Object::hasOwnProperty(uint index) const return false; } -ReturnedValue Object::construct(Managed *m, CallData *) +ReturnedValue Object::construct(const Managed *m, CallData *) { - return static_cast<Object *>(m)->engine()->throwTypeError(); + return static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::call(Managed *m, CallData *) +ReturnedValue Object::call(const Managed *m, CallData *) { - return static_cast<Object *>(m)->engine()->throwTypeError(); + return static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty) { - return static_cast<Object *>(m)->internalGet(name, hasProperty); + return static_cast<const Object *>(m)->internalGet(name, hasProperty); } -ReturnedValue Object::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty) { - return static_cast<Object *>(m)->internalGetIndexed(index, hasProperty); + return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty); } void Object::put(Managed *m, String *name, const Value &value) @@ -416,8 +415,7 @@ PropertyAttributes Object::queryIndexed(const Managed *m, uint index) return o->arrayData()->attributes(index); if (o->isStringObject()) { - String *s = static_cast<const StringObject *>(o)->d()->value.asString(); - if (index < (uint)s->d()->length()) + if (index < static_cast<const StringObject *>(o)->length()) return (Attr_NotWritable|Attr_NotConfigurable); } return Attr_Invalid; @@ -433,9 +431,9 @@ bool Object::deleteIndexedProperty(Managed *m, uint index) return static_cast<Object *>(m)->internalDeleteIndexedProperty(index); } -ReturnedValue Object::getLookup(Managed *m, Lookup *l) +ReturnedValue Object::getLookup(const Managed *m, Lookup *l) { - Object *o = static_cast<Object *>(m); + const Object *o = static_cast<const Object *>(m); PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -531,7 +529,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name while (it->arrayNode != o->sparseEnd()) { int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; - Heap::SparseArrayData *sa = static_cast<Heap::SparseArrayData *>(o->d()->arrayData); + Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>(); Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; @@ -548,7 +546,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name } // dense arrays while (it->arrayIndex < o->d()->arrayData->len) { - Heap::SimpleArrayData *sa = static_cast<Heap::SimpleArrayData *>(o->d()->arrayData); + Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; @@ -585,7 +583,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name } // Section 8.12.3 -ReturnedValue Object::internalGet(String *name, bool *hasProperty) +ReturnedValue Object::internalGet(String *name, bool *hasProperty) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -611,7 +609,7 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) return Encode::undefined(); } -ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) +ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const { Property *pd = 0; PropertyAttributes attrs; @@ -625,10 +623,12 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) break; } if (o->isStringObject()) { - pd = static_cast<StringObject *>(o.getPointer())->getIndex(index); - if (pd) { + ScopedString str(scope, static_cast<StringObject *>(o.getPointer())->getIndex(index)); + if (str) { attrs = (Attr_NotWritable|Attr_NotConfigurable); - break; + if (hasProperty) + *hasProperty = true; + return str.asReturnedValue(); } } o = o->prototype(); @@ -674,7 +674,7 @@ void Object::internalPut(String *name, const Value &value) goto reject; } else if (!attrs.isWritable()) goto reject; - else if (isArrayObject() && name->equals(engine()->id_length)) { + else if (isArrayObject() && name->equals(engine()->id_length())) { bool ok; uint l = value.asArrayLength(&ok); if (!ok) { @@ -710,7 +710,7 @@ void Object::internalPut(String *name, const Value &value) // Clause 5 if (pd && attrs.isAccessor()) { - assert(pd->setter() != 0); + Q_ASSERT(pd->setter() != 0); Scope scope(engine()); ScopedFunctionObject setter(scope, pd->setter()); @@ -745,8 +745,7 @@ void Object::internalPutIndexed(uint index, const Value &value) attrs = arrayData()->attributes(index); if (!pd && isStringObject()) { - pd = static_cast<StringObject *>(this)->getIndex(index); - if (pd) + if (index < static_cast<StringObject *>(this)->length()) // not writable goto reject; } @@ -784,7 +783,7 @@ void Object::internalPutIndexed(uint index, const Value &value) // Clause 5 if (pd && attrs.isAccessor()) { - assert(pd->setter() != 0); + Q_ASSERT(pd->setter() != 0); Scope scope(engine()); ScopedFunctionObject setter(scope, pd->setter()); @@ -858,8 +857,8 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const PropertyAttributes *cattrs; uint memberIndex; - if (isArrayObject() && name->equals(engine->id_length)) { - Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length)); + if (isArrayObject() && name->equals(engine->id_length())) { + Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length())); Property *lp = propertyAt(Heap::ArrayObject::LengthPropertyIndex); cattrs = internalClass()->propertyData.constData() + Heap::ArrayObject::LengthPropertyIndex; if (attrs.isEmpty() || p->isSubset(attrs, lp, *cattrs)) @@ -926,16 +925,16 @@ reject: bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs) { - Property *current = 0; + bool hasProperty = 0; // Clause 1 if (arrayData()) { - current = arrayData()->getProperty(index); - if (!current && isStringObject()) - current = static_cast<StringObject *>(this)->getIndex(index); + hasProperty = arrayData()->getProperty(index); + if (!hasProperty && isStringObject()) + hasProperty = (index < static_cast<StringObject *>(this)->length()); } - if (!current) { + if (!hasProperty) { // clause 3 if (!isExtensible()) goto reject; @@ -1097,7 +1096,7 @@ void Object::copyArrayData(Object *other) uint Object::getLength(const Managed *m) { Scope scope(static_cast<const Object *>(m)->engine()); - ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length)); + ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length())); return v->toUInt32(); } @@ -1137,7 +1136,7 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) - : Heap::Object(engine->arrayClass, engine->arrayPrototype.asObject()) + : Heap::Object(engine->arrayClass, engine->arrayPrototype()) { init(); Scope scope(engine); @@ -1155,14 +1154,14 @@ Heap::ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) a->setArrayLengthUnchecked(len); } -ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l) +ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); ScopedString name(scope, scope.engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (name->equals(scope.engine->id_length)) { + if (name->equals(scope.engine->id_length())) { // special case, as the property is on the object itself l->getter = Lookup::arrayLengthGetter; - ArrayObject *a = static_cast<ArrayObject *>(m); + const ArrayObject *a = static_cast<const ArrayObject *>(m); return a->memberData()->data[Heap::ArrayObject::LengthPropertyIndex].asReturnedValue(); } return Object::getLookup(m, l); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 71a997e133..671e207489 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -36,6 +36,9 @@ #include "qv4managed_p.h" #include "qv4memberdata_p.h" #include "qv4arraydata_p.h" +#include "qv4engine_p.h" +#include "qv4scopedvalue_p.h" +#include "qv4value_p.h" QT_BEGIN_NAMESPACE @@ -44,20 +47,16 @@ namespace QV4 { namespace Heap { struct Object : Base { - Object(ExecutionEngine *engine) - : internalClass(engine->emptyClass), - prototype(static_cast<Object *>(engine->objectPrototype.m)) - { - } + inline Object(ExecutionEngine *engine); Object(InternalClass *internal, QV4::Object *prototype); const Property *propertyAt(uint index) const { return reinterpret_cast<const Property *>(memberData->data + index); } Property *propertyAt(uint index) { return reinterpret_cast<Property *>(memberData->data + index); } InternalClass *internalClass; - Heap::Object *prototype; - MemberData *memberData; - ArrayData *arrayData; + Pointer<Object> prototype; + Pointer<MemberData> memberData; + Pointer<ArrayData> arrayData; }; } @@ -67,7 +66,7 @@ struct Object : Base { Q_MANAGED_CHECK \ typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ Data *d() const { return static_cast<Data *>(m); } @@ -77,24 +76,24 @@ struct Object : Base { typedef QV4::Heap::DataClass Data; \ typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ - static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ + static inline const QV4::VTable *staticVTable() { return &static_vtbl.vTable; } \ V4_MANAGED_SIZE_TEST \ QV4::Heap::DataClass *d() const { return static_cast<QV4::Heap::DataClass *>(m); } struct ObjectVTable { - ManagedVTable managedVTable; - ReturnedValue (*call)(Managed *, CallData *data); - ReturnedValue (*construct)(Managed *, CallData *data); - ReturnedValue (*get)(Managed *, String *name, bool *hasProperty); - ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty); + VTable vTable; + ReturnedValue (*call)(const Managed *, CallData *data); + ReturnedValue (*construct)(const Managed *, CallData *data); + ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty); + ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); void (*put)(Managed *, String *name, const Value &value); void (*putIndexed)(Managed *, uint index, const Value &value); PropertyAttributes (*query)(const Managed *, String *name); PropertyAttributes (*queryIndexed)(const Managed *, uint index); bool (*deleteProperty)(Managed *m, String *name); bool (*deleteIndexedProperty)(Managed *m, uint index); - ReturnedValue (*getLookup)(Managed *m, Lookup *l); + ReturnedValue (*getLookup)(const Managed *m, Lookup *l); void (*setLookup)(Managed *m, Lookup *l, const Value &v); uint (*getLength)(const Managed *m); void (*advanceIterator)(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); @@ -103,7 +102,7 @@ struct ObjectVTable #define DEFINE_OBJECT_VTABLE(classname) \ const QV4::ObjectVTable classname::static_vtbl = \ { \ - DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.managedVTable), \ + DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable), \ call, \ construct, \ get, \ @@ -145,11 +144,11 @@ struct Q_QML_EXPORT Object: Managed { Heap::Object *prototype() const { return d()->prototype; } bool setPrototype(Object *proto); - Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0); - Property *__getOwnProperty__(uint index, PropertyAttributes *attrs = 0); + void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); + void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs = 0) const; - Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const; + Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const; + Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const; bool hasProperty(String *name) const; bool hasProperty(uint index) const; @@ -272,9 +271,9 @@ public: } void ensureMemberIndex(uint idx); - inline ReturnedValue get(String *name, bool *hasProperty = 0) + inline ReturnedValue get(String *name, bool *hasProperty = 0) const { return vtable()->get(this, name, hasProperty); } - inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) + inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const { return vtable()->getIndexed(this, idx, hasProperty); } inline void put(String *name, const Value &v) { vtable()->put(this, name, v); } @@ -288,7 +287,7 @@ public: { return vtable()->deleteProperty(this, name); } bool deleteIndexedProperty(uint index) { return vtable()->deleteIndexedProperty(this, index); } - ReturnedValue getLookup(Lookup *l) + ReturnedValue getLookup(Lookup *l) const { return vtable()->getLookup(this, l); } void setLookup(Lookup *l, const Value &v) { vtable()->setLookup(this, l, v); } @@ -296,30 +295,30 @@ public: { vtable()->advanceIterator(this, it, name, index, p, attributes); } uint getLength() const { return vtable()->getLength(this); } - inline ReturnedValue construct(CallData *d) + inline ReturnedValue construct(CallData *d) const { return vtable()->construct(this, d); } - inline ReturnedValue call(CallData *d) + inline ReturnedValue call(CallData *d) const { return vtable()->call(this, d); } protected: static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue construct(Managed *m, CallData *); - static ReturnedValue call(Managed *m, CallData *); - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue construct(const Managed *m, CallData *); + static ReturnedValue call(const Managed *m, CallData *); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static void putIndexed(Managed *m, uint index, const Value &value); static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *m, String *name); static bool deleteIndexedProperty(Managed *m, uint index); - static ReturnedValue getLookup(Managed *m, Lookup *l); + static ReturnedValue getLookup(const Managed *m, Lookup *l); static void setLookup(Managed *m, Lookup *l, const Value &v); static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); private: - ReturnedValue internalGet(String *name, bool *hasProperty); - ReturnedValue internalGetIndexed(uint index, bool *hasProperty); + ReturnedValue internalGet(String *name, bool *hasProperty) const; + ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; void internalPut(String *name, const Value &value); void internalPutIndexed(uint index, const Value &value); bool internalDeleteProperty(String *name); @@ -331,6 +330,12 @@ private: namespace Heap { +inline Object::Object(ExecutionEngine *engine) + : internalClass(engine->emptyClass), + prototype(static_cast<Object *>(engine->objectPrototype()->m)) +{ +} + struct BooleanObject : Object { BooleanObject(InternalClass *ic, QV4::Object *prototype) : Object(ic, prototype), @@ -339,7 +344,7 @@ struct BooleanObject : Object { } BooleanObject(ExecutionEngine *engine, bool b) - : Object(engine->emptyClass, engine->booleanPrototype.asObject()), + : Object(engine->emptyClass, engine->booleanPrototype()), b(b) { } @@ -354,7 +359,7 @@ struct NumberObject : Object { } NumberObject(ExecutionEngine *engine, double val) - : Object(engine->emptyClass, engine->numberPrototype.asObject()), + : Object(engine->emptyClass, engine->numberPrototype()), value(val) { } @@ -367,7 +372,7 @@ struct ArrayObject : Object { }; ArrayObject(ExecutionEngine *engine) - : Heap::Object(engine->arrayClass, engine->arrayPrototype.asObject()) + : Heap::Object(engine->arrayClass, engine->arrayPrototype()) { init(); } ArrayObject(ExecutionEngine *engine, const QStringList &list); ArrayObject(InternalClass *ic, QV4::Object *prototype) @@ -400,7 +405,7 @@ struct ArrayObject: Object { void init(ExecutionEngine *engine); - static ReturnedValue getLookup(Managed *m, Lookup *l); + static ReturnedValue getLookup(const Managed *m, Lookup *l); using Object::getLength; static uint getLength(const Managed *m); @@ -454,14 +459,10 @@ inline void Object::arraySet(uint index, const Value &value) setArrayLengthUnchecked(index + 1); } -template<> -inline Object *value_cast(const Value &v) { - return v.asObject(); -} template<> -inline ArrayObject *value_cast(const Value &v) { - return v.asArrayObject(); +inline const ArrayObject *Value::as() const { + return isManaged() && m && m->vtable->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index f36ee554a7..d0e2650feb 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -35,6 +35,7 @@ #include "qv4stringobject_p.h" #include "qv4identifier_p.h" #include "qv4argumentsobject_p.h" +#include "qv4string_p.h" using namespace QV4; @@ -50,7 +51,7 @@ ObjectIterator::ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scrat init(o); } -ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) +ObjectIterator::ObjectIterator(Scope &scope, const Object *o, uint flags) : engine(scope.engine) , object(scope.alloc(1)) , current(scope.alloc(1)) @@ -62,7 +63,7 @@ ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) init(o); } -void ObjectIterator::init(Object *o) +void ObjectIterator::init(const Object *o) { object->m = o ? o->m : 0; current->m = o ? o->m : 0; @@ -83,7 +84,7 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper *name = 0; *index = UINT_MAX; - if (!object->asObject()) { + if (!object->as<Object>()) { *attrs = PropertyAttributes(); return; } @@ -92,19 +93,19 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper ScopedString n(scope); while (1) { - if (!current->asObject()) + if (!current->as<Object>()) break; while (1) { - current->asObject()->advanceIterator(this, name, index, pd, attrs); + current->as<Object>()->advanceIterator(this, name, index, pd, attrs); if (attrs->isEmpty()) break; // check the property is not already defined earlier in the proto chain if (current->heapObject() != object->heapObject()) { - o = object->asObject(); + o = object->as<Object>(); n = *name; bool shadowed = false; - while (o->asObject()->d() != current->heapObject()) { + while (o->d() != current->heapObject()) { if ((!!n && o->hasOwnProperty(n)) || (*index != UINT_MAX && o->hasOwnProperty(*index))) { shadowed = true; @@ -131,7 +132,7 @@ void ObjectIterator::next(Heap::String **name, uint *index, Property *pd, Proper ReturnedValue ObjectIterator::nextPropertyName(Value *value) { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; @@ -147,13 +148,13 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) if (!!name) return name->asReturnedValue(); - assert(index < UINT_MAX); + Q_ASSERT(index < UINT_MAX); return Encode(index); } ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; @@ -169,13 +170,13 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) if (!!name) return name->asReturnedValue(); - assert(index < UINT_MAX); + Q_ASSERT(index < UINT_MAX); return Encode(engine->newString(QString::number(index))); } ReturnedValue ObjectIterator::nextPropertyNameAsString() { - if (!object->asObject()) + if (!object->as<Object>()) return Encode::null(); PropertyAttributes attrs; diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index a7abd2ca10..ff568ba893 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -57,8 +57,8 @@ struct Q_QML_EXPORT ObjectIterator uint flags; ObjectIterator(ExecutionEngine *e, Value *scratch1, Value *scratch2, Object *o, uint flags); - ObjectIterator(Scope &scope, Object *o, uint flags); - void init(Object *o); + ObjectIterator(Scope &scope, const Object *o, uint flags); + void init(const Object *o); void next(Heap::String **name, uint *index, Property *pd, PropertyAttributes *attributes = 0); ReturnedValue nextPropertyName(Value *value); ReturnedValue nextPropertyNameAsString(Value *value); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 9356ea434e..41483e9ef5 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -34,10 +34,11 @@ #include "qv4objectproto_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" #include "qv4objectiterator_p.h" +#include "qv4string_p.h" #include <QtCore/QDateTime> #include <QtCore/QStringList> @@ -52,14 +53,14 @@ Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) +ReturnedValue ObjectCtor::construct(const Managed *that, CallData *callData) { - ObjectCtor *ctor = static_cast<ObjectCtor *>(that); + const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that); ExecutionEngine *v4 = ctor->engine(); Scope scope(v4); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { ScopedObject obj(scope, v4->newObject()); - ScopedObject proto(scope, ctor->get(v4->id_prototype)); + ScopedObject proto(scope, ctor->get(v4->id_prototype())); if (!!proto) obj->setPrototype(proto); return obj.asReturnedValue(); @@ -67,9 +68,9 @@ ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData) return RuntimeHelpers::toObject(scope.engine, callData->args[0]); } -ReturnedValue ObjectCtor::call(Managed *m, CallData *callData) +ReturnedValue ObjectCtor::call(const Managed *m, CallData *callData) { - ObjectCtor *ctor = static_cast<ObjectCtor *>(m); + const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m); ExecutionEngine *v4 = ctor->engine(); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) return v4->newObject()->asReturnedValue(); @@ -81,8 +82,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) Scope scope(v4); ScopedObject o(scope, this); - ctor->defineReadonlyProperty(v4->id_prototype, o); - ctor->defineReadonlyProperty(v4->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(v4->id_prototype(), o); + ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1); @@ -98,9 +99,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("keys"), method_keys, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(v4->id_toString, method_toString, 0); + defineDefaultProperty(v4->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); - defineDefaultProperty(v4->id_valueOf, method_valueOf, 0); + defineDefaultProperty(v4->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("hasOwnProperty"), method_hasOwnProperty, 1); defineDefaultProperty(QStringLiteral("isPrototypeOf"), method_isPrototypeOf, 1); defineDefaultProperty(QStringLiteral("propertyIsEnumerable"), method_propertyIsEnumerable, 1); @@ -109,9 +110,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) ScopedContext global(scope, scope.engine->rootContext()); ScopedProperty p(scope); - p->value = BuiltinFunction::create(global, v4->id___proto__, method_get_proto); - p->set = BuiltinFunction::create(global, v4->id___proto__, method_set_proto); - insertMember(v4->id___proto__, p, Attr_Accessor|Attr_NotEnumerable); + p->value = BuiltinFunction::create(global, v4->id___proto__(), method_get_proto); + p->set = BuiltinFunction::create(global, v4->id___proto__(), method_set_proto); + insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable); } ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) @@ -140,8 +141,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); PropertyAttributes attrs; - Property *desc = O->__getOwnProperty__(name, &attrs); - return fromPropertyDescriptor(scope.engine, desc, attrs); + Property desc; + O->getOwnProperty(name, &attrs, &desc); + return fromPropertyDescriptor(scope.engine, &desc, attrs); } ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) @@ -163,7 +165,7 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx) return ctx->engine()->throwTypeError(); ScopedObject newObject(scope, ctx->d()->engine->newObject()); - newObject->setPrototype(O->asObject()); + newObject->setPrototype(O->as<Object>()); if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { ctx->d()->callData->args[0] = newObject.asReturnedValue(); @@ -400,7 +402,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); if (!o) return Encode::undefined(); - ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString)); + ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString())); if (!f) return ctx->engine()->throwTypeError(); ScopedCallData callData(scope); @@ -462,7 +464,7 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); PropertyAttributes attrs; - o->__getOwnProperty__(p, &attrs); + o->getOwnProperty(p, &attrs); return Encode(attrs.isEnumerable()); } @@ -484,7 +486,7 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) if (!o) { if (!ctx->thisObject().isUndefined()) return Encode::undefined(); - o = ctx->d()->engine->globalObject(); + o = ctx->d()->engine->globalObject; } ScopedProperty pd(scope); @@ -512,7 +514,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) if (!o) { if (!ctx->thisObject().isUndefined()) return Encode::undefined(); - o = ctx->d()->engine->globalObject(); + o = ctx->d()->engine->globalObject; } ScopedProperty pd(scope); @@ -525,7 +527,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().asObject()); + ScopedObject o(scope, ctx->thisObject().as<Object>()); if (!o) return ctx->engine()->throwTypeError(); @@ -572,15 +574,15 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value desc->set = Primitive::emptyValue(); ScopedValue tmp(scope); - if (o->hasProperty(engine->id_enumerable)) - attrs->setEnumerable((tmp = o->get(engine->id_enumerable))->toBoolean()); + if (o->hasProperty(engine->id_enumerable())) + attrs->setEnumerable((tmp = o->get(engine->id_enumerable()))->toBoolean()); - if (o->hasProperty(engine->id_configurable)) - attrs->setConfigurable((tmp = o->get(engine->id_configurable))->toBoolean()); + if (o->hasProperty(engine->id_configurable())) + attrs->setConfigurable((tmp = o->get(engine->id_configurable()))->toBoolean()); - if (o->hasProperty(engine->id_get)) { - ScopedValue get(scope, o->get(engine->id_get)); - FunctionObject *f = get->asFunctionObject(); + if (o->hasProperty(engine->id_get())) { + ScopedValue get(scope, o->get(engine->id_get())); + FunctionObject *f = get->as<FunctionObject>(); if (f || get->isUndefined()) { desc->value = get; } else { @@ -590,9 +592,9 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(engine->id_set)) { - ScopedValue set(scope, o->get(engine->id_set)); - FunctionObject *f = set->asFunctionObject(); + if (o->hasProperty(engine->id_set())) { + ScopedValue set(scope, o->get(engine->id_set())); + FunctionObject *f = set->as<FunctionObject>(); if (f || set->isUndefined()) { desc->set = set; } else { @@ -602,22 +604,22 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(engine->id_writable)) { + if (o->hasProperty(engine->id_writable())) { if (attrs->isAccessor()) { engine->throwTypeError(); return; } - attrs->setWritable((tmp = o->get(engine->id_writable))->toBoolean()); + attrs->setWritable((tmp = o->get(engine->id_writable()))->toBoolean()); // writable forces it to be a data descriptor desc->value = Primitive::undefinedValue(); } - if (o->hasProperty(engine->id_value)) { + if (o->hasProperty(engine->id_value())) { if (attrs->isAccessor()) { engine->throwTypeError(); return; } - desc->value = o->get(engine->id_value); + desc->value = o->get(engine->id_value()); attrs->setType(PropertyAttributes::Data); } diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index 4e96681017..d571e50cd4 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -53,8 +53,8 @@ struct ObjectCtor: FunctionObject { V4_OBJECT2(ObjectCtor, FunctionObject) - static ReturnedValue construct(Managed *that, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct ObjectPrototype: Object diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 88dc1946b8..a21bf696aa 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4persistent_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4object_p.h" #include "PageAllocation.h" @@ -190,7 +190,7 @@ void PersistentValueStorage::mark(ExecutionEngine *e) Page *p = static_cast<Page *>(firstPage); while (p) { for (int i = 0; i < kEntriesPerPage; ++i) { - if (Managed *m = p->values[i].asManaged()) + if (Managed *m = p->values[i].as<Managed>()) m->mark(e); } drainMarkStack(e, markBase); @@ -312,6 +312,12 @@ WeakValue::WeakValue(const WeakValue &other) } } +WeakValue::WeakValue(ExecutionEngine *engine, const Value &value) +{ + val = engine->memoryManager->m_weakValues->allocate(); + *val = value; +} + WeakValue &WeakValue::operator=(const WeakValue &other) { if (!val) { diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index 7cac2ed95f..858734e9ed 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -33,7 +33,8 @@ #ifndef QV4PERSISTENT_H #define QV4PERSISTENT_H -#include "qv4value_inl_p.h" +#include "qv4value_p.h" +#include "qv4managed_p.h" QT_BEGIN_NAMESPACE @@ -96,7 +97,13 @@ public: Managed *asManaged() const { if (!val) return 0; - return val->asManaged(); + return val->as<Managed>(); + } + template<typename T> + T *as() const { + if (!val) + return 0; + return val->as<T>(); } ExecutionEngine *engine() const { @@ -122,6 +129,7 @@ class Q_QML_EXPORT WeakValue public: WeakValue() : val(0) {} WeakValue(const WeakValue &other); + WeakValue(ExecutionEngine *engine, const Value &value); WeakValue &operator=(const WeakValue &other); ~WeakValue(); @@ -138,7 +146,13 @@ public: Managed *asManaged() const { if (!val) return 0; - return val->asManaged(); + return val->as<Managed>(); + } + template <typename T> + T *as() const { + if (!val) + return 0; + return val->as<T>(); } ExecutionEngine *engine() const { diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index a7019d0558..d2628c7bd0 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -32,7 +32,8 @@ ****************************************************************************/ #include "qv4profiling_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> +#include <private/qv4string_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 1b55abd1f7..34d9cdadeb 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -35,7 +35,6 @@ #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4internalclass_p.h" QT_BEGIN_NAMESPACE @@ -73,8 +72,8 @@ struct Property { inline Heap::FunctionObject *getter() const { return value.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(value.heapObject()) : 0; } inline Heap::FunctionObject *setter() const { return set.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(set.heapObject()) : 0; } - inline void setGetter(FunctionObject *g) { value = Primitive::fromManaged(reinterpret_cast<Managed *>(g)); } - inline void setSetter(FunctionObject *s) { set = s ? Primitive::fromManaged(reinterpret_cast<Managed *>(s)) : Value::fromHeapObject(0); } + inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); } + inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : 0); } void copy(const Property *other, PropertyAttributes attrs) { value = other->value; @@ -85,8 +84,8 @@ struct Property { explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); } explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); } Property(FunctionObject *getter, FunctionObject *setter) { - value = Primitive::fromManaged(reinterpret_cast<Managed *>(getter)); - set = Primitive::fromManaged(reinterpret_cast<Managed *>(setter)); + value = reinterpret_cast<Managed *>(getter); + set = reinterpret_cast<Managed *>(setter); } Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) { value.m = reinterpret_cast<Heap::Base *>(getter); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 1e4718c208..4f6331c54b 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -55,6 +55,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4regexpobject_p.h> +#include <private/qv4dateobject_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4mm_p.h> #include <private/qqmlscriptstring_p.h> @@ -97,7 +98,7 @@ static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function) static QPair<QObject *, int> extractQtSignal(const Value &value) { if (value.isObject()) { - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedFunctionObject function(scope, value); if (function) @@ -240,8 +241,8 @@ Heap::QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) void QObjectWrapper::initializeBindings(ExecutionEngine *engine) { - engine->functionPrototype.asObject()->defineDefaultProperty(QStringLiteral("connect"), method_connect); - engine->functionPrototype.asObject()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect); + engine->functionPrototype()->defineDefaultProperty(QStringLiteral("connect"), method_connect); + engine->functionPrototype()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect); } QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const @@ -260,7 +261,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont } ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode, - bool *hasProperty, bool includeImports) + bool *hasProperty, bool includeImports) const { if (QQmlData::wasDeleted(d()->object)) { if (hasProperty) @@ -271,8 +272,8 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String QV4::Scope scope(engine()); QV4::ScopedString name(scope, n); - if (name->equals(scope.engine->id_destroy) || name->equals(scope.engine->id_toString)) { - int index = name->equals(scope.engine->id_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; + if (name->equals(scope.engine->id_destroy()) || name->equals(scope.engine->id_toString())) { + int index = name->equals(scope.engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; ScopedContext global(scope, scope.engine->rootContext()); QV4::ScopedValue method(scope, QV4::QObjectMethod::create(global, d()->object, index)); if (hasProperty) @@ -322,13 +323,12 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (hasProperty) *hasProperty = true; - ScopedContext ctx(scope, scope.engine->currentContext()); - return getProperty(d()->object, ctx, result); + return getProperty(scope.engine, d()->object, result); } -ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) { - QV4::Scope scope(ctx); + QV4::Scope scope(engine); QQmlData::flushPendingBinding(object, property->coreIndex); @@ -338,16 +338,16 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { - QV4::ScopedObject qmlcontextobject(scope, ctx->d()->engine->qmlContextObject()); + QV4::ScopedObject qmlcontextobject(scope, engine->qmlContextObject()); ScopedContext global(scope, scope.engine->rootContext()); return QV4::QObjectMethod::create(global, object, property->coreIndex, qmlcontextobject); } else if (property->isSignalHandler()) { - QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(ctx->d()->engine, object, property->coreIndex)); + QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(engine, object, property->coreIndex)); - QV4::ScopedString connect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("connect"))); - QV4::ScopedString disconnect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("disconnect"))); - handler->put(connect, QV4::ScopedValue(scope, ctx->d()->engine->functionPrototype.asObject()->get(connect))); - handler->put(disconnect, QV4::ScopedValue(scope, ctx->d()->engine->functionPrototype.asObject()->get(disconnect))); + QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect"))); + QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect"))); + handler->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect))); + handler->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect))); return handler.asReturnedValue(); } else { @@ -365,31 +365,32 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; - QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->d()->engine, object, *property, nptr)); + QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(engine, object, *property, nptr)); if (captureRequired) { if (property->accessors->notifier) { - if (n) - ep->captureProperty(n); + if (n && ep->propertyCapture) + ep->propertyCapture->captureProperty(n); } else { - ep->captureProperty(object, property->coreIndex, property->notifyIndex); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex); } } return rv->asReturnedValue(); } - if (captureRequired && ep && !property->isConstant()) - ep->captureProperty(object, property->coreIndex, property->notifyIndex); + if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) + ep->propertyCapture->captureProperty(object, property->coreIndex, property->notifyIndex); if (property->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeProperty(property->coreIndex); } else if (property->isDirect()) { - return LoadProperty<ReadAccessor::Direct>(ctx->d()->engine, object, *property, 0); + return LoadProperty<ReadAccessor::Direct>(engine, object, *property, 0); } else { - return LoadProperty<ReadAccessor::Indirect>(ctx->d()->engine, object, *property, 0); + return LoadProperty<ReadAccessor::Indirect>(engine, object, *property, 0); } } @@ -440,21 +441,21 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm Scope scope(engine); ScopedContext ctx(scope, engine->currentContext()); - setProperty(object, ctx, result, value); + setProperty(engine, object, result, value); return true; } -void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const Value &value) +void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value) { if (!property->isWritable() && !property->isQList()) { QString error = QLatin1String("Cannot assign to read-only property \"") + property->name(object) + QLatin1Char('\"'); - ctx->engine()->throwTypeError(error); + engine->throwTypeError(error); return; } QQmlBinding *newBinding = 0; - QV4::Scope scope(ctx); + QV4::Scope scope(engine); QV4::ScopedFunctionObject f(scope, value); if (f) { if (!f->isBinding()) { @@ -465,25 +466,25 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; } } else { // binding assignment. - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); + QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); newBinding = new QQmlBinding(value, object, callingQmlContext); - newBinding->setTarget(object, *property, callingQmlContext); + newBinding->setTarget(object, *property); } } - QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding); - if (oldBinding) - oldBinding->destroy(); + if (newBinding) + QQmlPropertyPrivate::setBinding(newBinding); + else + QQmlPropertyPrivate::removeBinding(object, property->encodedIndex()); if (!newBinding && property->isVarProperty()) { // allow assignment of "special" values (null, undefined, function) to var properties @@ -510,16 +511,16 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else if (value.isUndefined() && property->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) { - PROPERTY_STORE(QJSValue, QJSValue(ctx->d()->engine, value.asReturnedValue())); + PROPERTY_STORE(QJSValue, QJSValue(scope.engine, value.asReturnedValue())); } else if (value.isUndefined() && property->propType != qMetaTypeId<QQmlScriptString>()) { QString error = QLatin1String("Cannot assign [undefined] to "); if (!QMetaType::typeName(property->propType)) error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; - } else if (value.asFunctionObject()) { + } else if (value.as<FunctionObject>()) { // this is handled by the binding creation above } else if (property->propType == QMetaType::Int && value.isNumber()) { PROPERTY_STORE(int, value.asDouble()); @@ -548,11 +549,11 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else { QVariant v; if (property->isQList()) - v = ctx->d()->engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); + v = scope.engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); else - v = ctx->d()->engine->toVariant(value, property->propType); + v = scope.engine->toVariant(value, property->propType); - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); + QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; @@ -566,7 +567,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(targetTypeName); - ctx->engine()->throwError(error); + scope.engine->throwError(error); return; } } @@ -639,7 +640,7 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine) engine->m_multiplyWrappedQObjects->mark(object, engine); } -ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) { if (QQmlData::wasDeleted(object)) return QV4::Encode::null(); @@ -651,10 +652,10 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return getProperty(object, ctx, property, captureRequired); + return getProperty(engine, object, property, captureRequired); } -void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Value &value) +void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value) { if (QQmlData::wasDeleted(d()->object)) return; @@ -666,14 +667,14 @@ void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return setProperty(d()->object, ctx, property, value); + return setProperty(engine, d()->object, property, value); } bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) { Q_ASSERT(a->as<QV4::QObjectWrapper>()); QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a); - QV4::Object *o = b->asObject(); + QV4::Object *o = b->as<Object>(); if (o) { if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>()) return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object(); @@ -689,10 +690,10 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) return (engine->memoryManager->alloc<QV4::QObjectWrapper>(engine, object))->asReturnedValue(); } -QV4::ReturnedValue QObjectWrapper::get(Managed *m, String *name, bool *hasProperty) +QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *hasProperty) { - QObjectWrapper *that = static_cast<QObjectWrapper*>(m); - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(that->engine()); + const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); + QQmlContextData *qmlContext = that->engine()->callingQmlContext(); return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true); } @@ -704,7 +705,7 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value) if (v4->hasException || QQmlData::wasDeleted(that->d()->object)) return; - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); + QQmlContextData *qmlContext = v4->callingQmlContext(); if (!setQmlProperty(v4, qmlContext, that->d()->object, name, QV4::QObjectWrapper::IgnoreRevision, value)) { QQmlData *ddata = QQmlData::get(that->d()->object); // Types created by QML are not extensible at run-time, but for other QObjects we can store them @@ -723,10 +724,10 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) { const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); ExecutionEngine *engine = that->engine(); - QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(engine); + QQmlContextData *qmlContext = engine->callingQmlContext(); QQmlPropertyData local; if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local) - || name->equals(engine->id_destroy) || name->equals(engine->id_toString)) + || name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) return QV4::Attr_Data; else return QV4::Object::query(m, name); @@ -750,7 +751,6 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::Strin const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject; const int propertyCount = mo->propertyCount(); if (it->arrayIndex < static_cast<uint>(propertyCount)) { - // #### GC Scope scope(that->engine()); ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); *name = propName->d(); @@ -766,7 +766,6 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::Strin ++it->arrayIndex; if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) continue; - // #### GC Scope scope(that->engine()); ScopedString methodName(scope, that->engine()->newString(QString::fromUtf8(method.name()))); *name = methodName->d(); @@ -816,7 +815,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QV4::ScopedFunctionObject f(scope, This->function.value()); QV4::ScopedCallData callData(scope, argCount); - callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject()->asReturnedValue() : This->thisObject.value(); + callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value(); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; if (type == qMetaTypeId<QVariant>()) { @@ -1234,7 +1233,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } - } else if (actual.asDateObject()) { + } else if (actual.as<DateObject>()) { switch (conversionType) { case QMetaType::QDateTime: return 0; @@ -1252,7 +1251,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } - } else if (actual.asArrayObject()) { + } else if (actual.as<ArrayObject>()) { switch (conversionType) { case QMetaType::QJsonArray: return 3; @@ -1281,7 +1280,7 @@ static int MatchScore(const QV4::Value &actual, int conversionType) return 10; } } - } else if (QV4::Object *obj = actual.asObject()) { + } else if (const Object *obj = actual.as<Object>()) { if (obj->as<QV4::VariantObject>()) { if (conversionType == qMetaTypeId<QVariant>()) return 0; @@ -1611,9 +1610,9 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q type = callType; } else if (callType == QMetaType::QObjectStar) { qobjectPtr = 0; - if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) qobjectPtr = qobjectWrapper->object(); - else if (QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) + else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) queryEngine = qmlTypeWrapper->isSingleton(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { @@ -1635,7 +1634,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q } } else { QObject *o = 0; - if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) o = qobjectWrapper->object(); qlistPtr->append(o); } @@ -1759,14 +1758,14 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in return method.asReturnedValue(); } -ReturnedValue QObjectMethod::create(ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal) +ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal) { Scope valueScope(scope); Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope)); method->d()->propertyCache = valueType->d()->propertyCache; method->d()->index = index; method->d()->qmlGlobal = qmlGlobal; - method->d()->valueTypeWrapper = valueType; + method->d()->valueTypeWrapper = *valueType; return method.asReturnedValue(); } @@ -1782,7 +1781,7 @@ const QMetaObject *Heap::QObjectMethod::metaObject() return object->metaObject(); } -QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) +QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) const { QString result; if (const QMetaObject *metaObject = d()->metaObject()) { @@ -1808,7 +1807,7 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) return ctx->d()->engine->newString(result)->asReturnedValue(); } -QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) +QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const { if (!d()->object) return Encode::undefined(); @@ -1827,13 +1826,13 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con return Encode::undefined(); } -ReturnedValue QObjectMethod::call(Managed *m, CallData *callData) +ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) { - QObjectMethod *This = static_cast<QObjectMethod*>(m); + const QObjectMethod *This = static_cast<const QObjectMethod*>(m); return This->callInternal(callData); } -ReturnedValue QObjectMethod::callInternal(CallData *callData) +ReturnedValue QObjectMethod::callInternal(CallData *callData) const { Scope scope(engine()); ScopedContext context(scope, scope.engine->currentContext()); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 24e8b29e08..324f598ad9 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -54,7 +54,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qintrusivelist_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -104,7 +104,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object QObject *object() const { return d()->object.data(); } - ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false); + ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false) const; static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0); static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); @@ -114,21 +114,21 @@ struct Q_QML_EXPORT QObjectWrapper : public Object using Object::get; - static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired); - void setProperty(ExecutionContext *ctx, int propertyIndex, const Value &value); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired); + void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value); protected: static bool isEqualTo(Managed *that, Managed *o); private: - static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true); - static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const Value &value); + static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true); + static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value); static ReturnedValue create(ExecutionEngine *engine, QObject *object); QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); @@ -149,17 +149,17 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject enum { DestroyMethod = -1, ToStringMethod = -2 }; static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal = Primitive::undefinedValue()); - static ReturnedValue create(QV4::ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal = Primitive::undefinedValue()); + static ReturnedValue create(QV4::ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index, const Value &qmlGlobal = Primitive::undefinedValue()); int methodIndex() const { return d()->index; } QObject *object() const { return d()->object.data(); } - QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx); - QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc); + QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const; + QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const; - static ReturnedValue call(Managed *, CallData *callData); + static ReturnedValue call(const Managed *, CallData *callData); - ReturnedValue callInternal(CallData *callData); + ReturnedValue callInternal(CallData *callData) const; static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 8e18a5fbdd..31fee534ad 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -34,16 +34,16 @@ #include "qv4regexp_p.h" #include "qv4engine_p.h" #include "qv4scopedvalue_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> using namespace QV4; RegExpCache::~RegExpCache() { - for (RegExpCache::Iterator it = begin(), e = end(); - it != e; ++it) - it.value()->cache = 0; - clear(); + for (RegExpCache::Iterator it = begin(), e = end(); it != e; ++it) { + if (RegExp *re = it.value().as<RegExp>()) + re->d()->cache = 0; + } } DEFINE_MANAGED_VTABLE(RegExp); @@ -68,19 +68,18 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo RegExpCacheKey key(pattern, ignoreCase, multiline); RegExpCache *cache = engine->regExpCache; - if (cache) { - if (Heap::RegExp *result = cache->value(key)) - return result; - } + if (!cache) + cache = engine->regExpCache = new RegExpCache; + + QV4::WeakValue &cachedValue = (*cache)[key]; + if (QV4::RegExp *result = cachedValue.as<RegExp>()) + return result->d(); Scope scope(engine); Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline)); - if (!cache) - cache = engine->regExpCache = new RegExpCache; - result->d()->cache = cache; - cache->insert(key, result->d()); + cachedValue.set(engine, result); return result->d(); } diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 819e31e5f1..af6e346ea8 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -133,8 +133,7 @@ inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re) inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.pattern, seed); } -// ### GC -class RegExpCache : public QHash<RegExpCacheKey, Heap::RegExp*> +class RegExpCache : public QHash<RegExpCacheKey, WeakValue> { public: ~RegExpCache(); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f6e88e62b7..329e5d2c56 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4regexp_p.h" #include "qv4stringobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> @@ -75,7 +75,7 @@ Heap::RegExpObject::RegExpObject(InternalClass *ic, QV4::Object *prototype) } Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global) - : Heap::Object(engine->emptyClass, engine->regExpPrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->regExpPrototype()) , value(value->d()) , global(global) { @@ -88,7 +88,7 @@ Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *valu // The conversion is not 100% exact since ECMA regexp and QRegExp // have different semantics/flags, but we try to do our best. Heap::RegExpObject::RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re) - : Heap::Object(engine->emptyClass, engine->regExpPrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->regExpPrototype()) { value = 0; global = false; @@ -174,7 +174,7 @@ void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) Property *RegExpObject::lastIndexProperty() { - Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex)); + Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); return propertyAt(0); } @@ -231,14 +231,14 @@ Heap::RegExpCtor::RegExpCtor(QV4::ExecutionContext *scope) void Heap::RegExpCtor::clearLastMatch() { lastMatch = Primitive::nullValue(); - lastInput = internalClass->engine->id_empty; + lastInput = internalClass->engine->id_empty()->d(); lastMatchStart = 0; lastMatchEnd = 0; } -ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) +ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); + Scope scope(static_cast<const Object *>(m)->engine()); ScopedContext ctx(scope, scope.engine->currentContext()); ScopedValue r(scope, callData->argument(0)); @@ -286,7 +286,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); } -ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) +ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData) { if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) { if (callData->argc == 1 || callData->args[1].isUndefined()) @@ -300,7 +300,7 @@ void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) { RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); This->lastMatch.mark(e); - This->lastInput.mark(e); + This->lastInput->mark(e); FunctionObject::markObjects(that, e); } @@ -310,8 +310,8 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) ScopedObject o(scope); ScopedObject ctor(scope, constructor); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(2)); // Properties deprecated in the spec but required by "the web" :( ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, 0); @@ -337,7 +337,7 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(QStringLiteral("exec"), method_exec, 1); defineDefaultProperty(QStringLiteral("test"), method_test, 1); - defineDefaultProperty(engine->id_toString, method_toString, 0); + defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("compile"), method_compile, 2); } @@ -363,7 +363,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint)); const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); regExpCtor->d()->clearLastMatch(); if (result == -1) { @@ -372,7 +372,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } // fill in result data - ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype.asObject())); + ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype())); int len = r->value()->captureCount(); array->arrayReserve(len); ScopedValue v(scope); @@ -388,7 +388,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; - dd->lastInput = arg->stringValue(); + dd->lastInput = arg->stringValue()->d(); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; @@ -425,7 +425,7 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) ScopedCallData callData(scope, ctx->argc()); memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value)); - Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData)); + Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(callData)); r->d()->value = re->value(); r->d()->global = re->global(); @@ -436,7 +436,7 @@ template <int index> ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); if (result->isUndefined()) return ctx->d()->engine->newString()->asReturnedValue(); @@ -446,7 +446,7 @@ ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined()); if (result->isUndefined()) return ctx->d()->engine->newString()->asReturnedValue(); @@ -455,13 +455,13 @@ ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) { - return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastInput().asReturnedValue(); + return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastInput()->asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue(); } @@ -469,7 +469,7 @@ ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index f5f255faf5..29d20614de 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -61,14 +61,14 @@ struct RegExpObject : Object { RegExpObject(QV4::ExecutionEngine *engine, QV4::RegExp *value, bool global); RegExpObject(QV4::ExecutionEngine *engine, const QRegExp &re); - RegExp *value; + Pointer<RegExp> value; bool global; }; struct RegExpCtor : FunctionObject { RegExpCtor(QV4::ExecutionContext *scope); Value lastMatch; - StringValue lastInput; + Pointer<String> lastInput; int lastMatchStart; int lastMatchEnd; void clearLastMatch(); @@ -117,12 +117,12 @@ struct RegExpCtor: FunctionObject V4_OBJECT2(RegExpCtor, FunctionObject) Value lastMatch() { return d()->lastMatch; } - StringValue lastInput() { return d()->lastInput; } + Heap::String *lastInput() { return d()->lastInput; } int lastMatchStart() { return d()->lastMatchStart; } int lastMatchEnd() { return d()->lastMatchEnd; } - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -146,7 +146,7 @@ struct RegExpPrototype: RegExpObject }; inline Heap::RegExpPrototype::RegExpPrototype(ExecutionEngine *e) - : RegExpObject(e->emptyClass, e->objectPrototype.asObject()) + : RegExpObject(e->emptyClass, e->objectPrototype()) { } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index c31de6a9f0..3006ec9fe5 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -40,6 +40,7 @@ #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" #include "qv4objectiterator_p.h" +#include "qv4dateobject_p.h" #include "qv4lookup_p.h" #include "qv4function_p.h" #include "private/qlocale_tools_p.h" @@ -313,14 +314,14 @@ ReturnedValue Runtime::deleteName(ExecutionEngine *engine, int nameIndex) QV4::ReturnedValue Runtime::instanceof(ExecutionEngine *engine, const Value &left, const Value &right) { Scope scope(engine); - ScopedFunctionObject f(scope, right.asFunctionObject()); + ScopedFunctionObject f(scope, right.as<FunctionObject>()); if (!f) return engine->throwTypeError(); if (f->isBoundFunction()) f = static_cast<BoundFunction *>(f.getPointer())->target(); - ScopedObject v(scope, left.asObject()); + ScopedObject v(scope, left.as<Object>()); if (!v) return Encode(false); @@ -380,10 +381,10 @@ Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double n return engine->newString(qstr); } -ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) +ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint) { if (typeHint == PREFERREDTYPE_HINT) { - if (object->asDateObject()) + if (object->as<DateObject>()) typeHint = STRING_HINT; else typeHint = NUMBER_HINT; @@ -393,18 +394,18 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) if (engine->hasException) return Encode::undefined(); - StringValue *meth1 = &engine->id_toString; - StringValue *meth2 = &engine->id_valueOf; + String *meth1 = engine->id_toString(); + String *meth2 = engine->id_valueOf(); if (typeHint == NUMBER_HINT) qSwap(meth1, meth2); Scope scope(engine); ScopedCallData callData(scope, 0); - callData->thisObject = object; + callData->thisObject = *object; - ScopedValue conv(scope, object->get(*meth1)); - if (FunctionObject *o = conv->asFunctionObject()) { + ScopedValue conv(scope, object->get(meth1)); + if (FunctionObject *o = conv->as<FunctionObject>()) { ScopedValue r(scope, o->call(callData)); if (r->isPrimitive()) return r->asReturnedValue(); @@ -413,8 +414,8 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) if (engine->hasException) return Encode::undefined(); - conv = object->get(*meth2); - if (FunctionObject *o = conv->asFunctionObject()) { + conv = object->get(meth2); + if (FunctionObject *o = conv->as<FunctionObject>()) { ScopedValue r(scope, o->call(callData)); if (r->isPrimitive()) return r->asReturnedValue(); @@ -437,7 +438,7 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val return engine->newBooleanObject(value.booleanValue()); case Value::Managed_Type: Q_ASSERT(value.isString()); - return engine->newStringObject(value); + return engine->newStringObject(value.stringValue()); case Value::Integer_Type: default: // double return engine->newNumberObject(value.asDouble()); @@ -450,14 +451,14 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined->d(); + return engine->id_undefined()->d(); case Value::Null_Type: - return engine->id_null->d(); + return engine->id_null()->d(); case Value::Boolean_Type: if (value.booleanValue()) - return engine->id_true->d(); + return engine->id_true()->d(); else - return engine->id_false->d(); + return engine->id_false()->d(); case Value::Managed_Type: if (value.isString()) return value.stringValue()->d(); @@ -481,14 +482,14 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined->d(); + return engine->id_undefined()->d(); case Value::Null_Type: - return engine->id_null->d(); + return engine->id_null()->d(); case Value::Boolean_Type: if (value.booleanValue()) - return engine->id_true->d(); + return engine->id_true()->d(); else - return engine->id_false->d(); + return engine->id_false()->d(); case Value::Managed_Type: if (value.isString()) return value.stringValue()->d(); @@ -575,7 +576,7 @@ ReturnedValue Runtime::getElement(ExecutionEngine *engine, const Value &object, ScopedObject o(scope, object); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); } @@ -909,7 +910,7 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionEngine *engine, uint index, Cal return engine->throwTypeError(); ScopedString name(scope, engine->currentContext()->compilationUnit->runtimeStrings[l->nameIndex]); - if (o->d() == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) + if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); return o->call(callData); @@ -931,7 +932,7 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI if (base) callData->thisObject = base; - FunctionObject *o = func->asFunctionObject(); + FunctionObject *o = func->as<FunctionObject>(); if (!o) { QString objectAsString = QStringLiteral("[null]"); if (base) @@ -940,7 +941,7 @@ ReturnedValue Runtime::callActivationProperty(ExecutionEngine *engine, int nameI return engine->throwTypeError(msg); } - if (o->d() == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) { + if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) { return static_cast<EvalFunction *>(o)->evalCall(callData, true); } @@ -1034,7 +1035,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int if (scope.engine->hasException) return Encode::undefined(); - Object *f = func->asObject(); + Object *f = func->as<Object>(); if (!f) return engine->throwTypeError(); @@ -1043,7 +1044,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionEngine *engine, int ReturnedValue Runtime::constructValue(ExecutionEngine *engine, const Value &func, CallData *callData) { - Object *f = func.asObject(); + const Object *f = func.as<Object>(); if (!f) return engine->throwTypeError(); @@ -1089,24 +1090,24 @@ ReturnedValue Runtime::typeofValue(ExecutionEngine *engine, const Value &value) ScopedString res(scope); switch (value.type()) { case Value::Undefined_Type: - res = engine->id_undefined; + res = engine->id_undefined(); break; case Value::Null_Type: - res = engine->id_object; + res = engine->id_object(); break; case Value::Boolean_Type: - res = engine->id_boolean; + res = engine->id_boolean(); break; case Value::Managed_Type: if (value.isString()) - res = engine->id_string; - else if (value.objectValue()->asFunctionObject()) - res = engine->id_function; + res = engine->id_string(); + else if (value.objectValue()->as<FunctionObject>()) + res = engine->id_function(); else - res = engine->id_object; // ### implementation-defined + res = engine->id_object(); // ### implementation-defined break; default: - res = engine->id_number; + res = engine->id_number(); break; } return res.asReturnedValue(); @@ -1199,7 +1200,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * { Scope scope(engine); QV4::InternalClass *klass = engine->currentContext()->compilationUnit->runtimeClasses[classId]; - ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype.asObject())); + ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype())); { bool needSparseArray = arrayGetterSetterCountAndFlags >> 30; @@ -1239,7 +1240,7 @@ ReturnedValue Runtime::objectLiteral(ExecutionEngine *engine, const QV4::Value * QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionEngine *engine) { - Q_ASSERT(engine->currentContext()->type >= Heap::ExecutionContext::Type_CallContext); + Q_ASSERT(engine->currentContext()->type == Heap::ExecutionContext::Type_CallContext); Scope scope(engine); Scoped<CallContext> c(scope, static_cast<Heap::CallContext *>(engine->currentContext())); return (engine->memoryManager->alloc<ArgumentsObject>(c))->asReturnedValue(); @@ -1334,14 +1335,12 @@ ReturnedValue Runtime::regexpLiteral(ExecutionEngine *engine, int id) ReturnedValue Runtime::getQmlIdArray(NoThrowEngine *engine) { Q_ASSERT(engine->qmlContextObject()); - Scope scope(engine); - Scoped<QmlContextWrapper> wrapper(scope, engine->qmlContextObject()); - return wrapper->idObjectsArray(); + return engine->qmlContextObject()->asReturnedValue(); } ReturnedValue Runtime::getQmlContextObject(NoThrowEngine *engine) { - QQmlContextData *context = QmlContextWrapper::callingContext(engine); + QQmlContextData *context = engine->callingQmlContext(); if (!context) return Encode::undefined(); return QObjectWrapper::wrap(engine, context->contextObject); @@ -1349,9 +1348,7 @@ ReturnedValue Runtime::getQmlContextObject(NoThrowEngine *engine) ReturnedValue Runtime::getQmlScopeObject(NoThrowEngine *engine) { - Scope scope(engine); - QV4::Scoped<QmlContextWrapper> c(scope, engine->qmlContextObject()); - return QObjectWrapper::wrap(engine, c->getScopeObject()); + return QObjectWrapper::wrap(engine, engine->qmlScopeObject()); } ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1362,21 +1359,17 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionEngine *engine, const Valu engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired); } QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex) { - Scope scope(engine); - QV4::Scoped<QmlContextWrapper> c(scope, engine->qmlContextObject()); - QObject *scopeObject = c->getScopeObject(); + QObject *scopeObject = engine->qmlScopeObject(); QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject); QJSEngine *jsEngine = engine->jsEngine(); QQmlData::ensurePropertyCache(jsEngine, attachedObject); - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true); + return QV4::QObjectWrapper::getProperty(engine, attachedObject, propertyIndex, /*captureRequired*/true); } ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) @@ -1387,8 +1380,7 @@ ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionEngine *engine, c scope.engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } - ScopedContext ctx(scope, engine->currentContext()); - return QV4::QObjectWrapper::getProperty(wrapper->singletonObject(), ctx, propertyIndex, captureRequired); + return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->singletonObject(), propertyIndex, captureRequired); } void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value) @@ -1399,13 +1391,12 @@ void Runtime::setQmlQObjectProperty(ExecutionEngine *engine, const Value &object engine->throwTypeError(QStringLiteral("Cannot write property of null")); return; } - ScopedContext ctx(scope, engine->currentContext()); - wrapper->setProperty(ctx, propertyIndex, value); + wrapper->setProperty(engine, propertyIndex, value); } ReturnedValue Runtime::getQmlImportedScripts(NoThrowEngine *engine) { - QQmlContextData *context = QmlContextWrapper::callingContext(engine); + QQmlContextData *context = engine->callingQmlContext(); if (!context) return Encode::undefined(); return context->importedScripts.value(); @@ -1425,7 +1416,7 @@ void Runtime::convertThisToObject(ExecutionEngine *engine) if (t->isObject()) return; if (t->isNullOrUndefined()) { - *t = engine->globalObject()->asReturnedValue(); + *t = engine->globalObject->asReturnedValue(); } else { *t = t->toObject(engine)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index f2f90bbc15..e8ebccc17b 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -34,8 +34,9 @@ #define QMLJS_RUNTIME_H #include "qv4global_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4context_p.h" +#include "qv4engine_p.h" #include "qv4math_p.h" #include <QtCore/qnumeric.h> @@ -218,7 +219,7 @@ struct Q_QML_PRIVATE_EXPORT Runtime { }; struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { - static ReturnedValue objectDefaultValue(Object *object, int typeHint); + static ReturnedValue objectDefaultValue(const Object *object, int typeHint); static ReturnedValue toPrimitive(const Value &value, int typeHint); static double stringToNumber(const QString &s); @@ -243,7 +244,7 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { #ifndef V4_BOOTSTRAP inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, int typeHint) { - Object *o = value.asObject(); + const Object *o = value.as<Object>(); if (!o) return value.asReturnedValue(); return RuntimeHelpers::objectDefaultValue(o, typeHint); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 908248f0f0..02b038f247 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -85,10 +85,7 @@ struct Scope { #ifndef QT_NO_DEBUG size += nValues; #endif - Value *ptr = engine->jsStackTop; - engine->jsStackTop = ptr + nValues; - memset(ptr, 0, nValues*sizeof(Value)); - return ptr; + return engine->jsAlloca(nValues); } bool hasException() const { @@ -202,7 +199,7 @@ struct Scoped { enum _Convert { Convert }; - inline void setPointer(Managed *p) { + inline void setPointer(const Managed *p) { ptr->m = p ? p->m : 0; #if QT_POINTER_SIZE == 4 ptr->tag = QV4::Value::Managed_Type; @@ -221,11 +218,10 @@ struct Scoped #endif } - // ### GC FIX casting below to be safe Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -235,7 +231,7 @@ struct Scoped Value v; v = o; ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -243,7 +239,7 @@ struct Scoped Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(*v.ptr)); + setPointer(v.ptr->as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -261,7 +257,7 @@ struct Scoped Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsStackTop++; - setPointer(v ? value_cast<T>(*v) : 0); + setPointer(v ? v->as<T>() : 0); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -287,7 +283,7 @@ struct Scoped Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; - setPointer(value_cast<T>(QV4::Value::fromReturnedValue(v))); + setPointer(QV4::Value::fromReturnedValue(v).as<T>()); #ifndef QT_NO_DEBUG ++scope.size; #endif @@ -302,9 +298,7 @@ struct Scoped } Scoped<T> &operator=(Heap::Base *o) { - Value v; - v = o; - setPointer(value_cast<T>(v)); + setPointer(Value::fromHeapObject(o).as<T>()); return *this; } Scoped<T> &operator=(typename T::Data *t) { @@ -312,16 +306,16 @@ struct Scoped return *this; } Scoped<T> &operator=(const Value &v) { - setPointer(value_cast<T>(v)); + setPointer(v.as<T>()); return *this; } Scoped<T> &operator=(Value *v) { - setPointer(v ? value_cast<T>(*v) : 0); + setPointer(v ? v->as<T>() : 0); return *this; } Scoped<T> &operator=(const ReturnedValue &v) { - setPointer(value_cast<T>(QV4::Value::fromReturnedValue(v))); + setPointer(QV4::Value::fromReturnedValue(v).as<T>()); return *this; } @@ -401,33 +395,6 @@ inline Value &Value::operator=(const Scoped<T> &t) return *this; } -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator =(T *t) -{ - m = t ? t->m : 0; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; -#endif - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v) -{ - m = v.ptr->m; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; -#endif - return *this; -} - -template<typename T> -inline TypedValue<T> &TypedValue<T>::operator=(const TypedValue<T> &t) -{ - val = t.val; - return *this; -} - struct ScopedProperty { ScopedProperty(Scope &scope) diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 4fde0e2445..576488275e 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4script_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4functionobject_p.h" #include "qv4function_p.h" #include "qv4context_p.h" @@ -44,6 +44,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlengine_p.h> +#include <private/qv4profiling_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> #include <private/qqmlcontextwrapper_p.h> @@ -86,8 +87,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlBindingWrapper); DEFINE_OBJECT_VTABLE(CompilationUnitHolder); -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::Object *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval, /*createProto = */ false) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) , qml(qml->d()) { Q_ASSERT(scope->inUse()); @@ -97,46 +98,43 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Functio function->compilationUnit->addref(); Scope s(scope); - Scoped<QV4::QmlBindingWrapper> o(s, this); + Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - - ScopedContext ctx(s, s.engine->currentContext()); - o->d()->qmlContext = ctx->newQmlContext(o, qml); - s.engine->popContext(); + this->scope = scope->newQmlContext(qml); + internalClass->engine->popContext(); } -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::Object *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval, /*createProto = */ false) +Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml) + : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) , qml(qml->d()) { Q_ASSERT(scope->inUse()); Scope s(scope); - Scoped<QV4::QmlBindingWrapper> o(s, this); - - o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); + Scoped<QV4::QmlBindingWrapper> protectThis(s, this); - ScopedContext ctx(s, s.engine->currentContext()); - o->d()->qmlContext = ctx->newQmlContext(o, qml); - s.engine->popContext(); + this->scope = scope->newQmlContext(qml); + internalClass->engine->popContext(); } -ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) +ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) { - ExecutionEngine *engine = static_cast<Object *>(that)->engine(); - CHECK_STACK_LIMITS(engine); + const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); + ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); + if (v4->hasException) + return Encode::undefined(); + CHECK_STACK_LIMITS(v4); - Scope scope(engine); - QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that); - if (!This->function()) + Scope scope(v4); + QV4::Function *f = This->function(); + if (!f) return QV4::Encode::undefined(); - Scoped<CallContext> ctx(scope, This->d()->qmlContext); - std::fill(ctx->d()->locals, ctx->d()->locals + ctx->d()->function->varCount(), Primitive::undefinedValue()); - engine->pushContext(ctx); - ScopedValue result(scope, This->function()->code(engine, This->function()->codeData)); - engine->popContext(); + ScopedContext context(scope, v4->currentContext()); + Scoped<CallContext> ctx(scope, context->newCallContext(This, callData)); + + ExecutionContextSaver ctxSaver(scope, context); + ScopedValue result(scope, Q_V4_PROFILE(v4, f)); return result->asReturnedValue(); } @@ -147,14 +145,12 @@ void QmlBindingWrapper::markObjects(Heap::Base *m, ExecutionEngine *e) if (wrapper->qml) wrapper->qml->mark(e); FunctionObject::markObjects(m, e); - if (wrapper->qmlContext) - wrapper->qmlContext->mark(e); } static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) { QV4::Scope scope(ctx); - QV4::Scoped<CallContext> signalEmittingContext(scope, static_cast<Heap::CallContext *>(ctx->d()->parent)); + QV4::Scoped<CallContext> signalEmittingContext(scope, ctx->d()->parent.cast<Heap::CallContext>()); Q_ASSERT(signalEmittingContext && signalEmittingContext->d()->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext); return signalEmittingContext->argument(parameterIndex); } @@ -163,10 +159,10 @@ Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContex { ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); QV4::Scope valueScope(engine); - QV4::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); + QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); ScopedContext global(valueScope, valueScope.engine->rootContext()); QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScopeObject)); - QV4::Scoped<CallContext> wrapperContext(valueScope, wrapper->context()); + QV4::Scoped<QmlContext> wrapperContext(valueScope, wrapper->context()); if (!signalParameters.isEmpty()) { if (error) @@ -214,7 +210,7 @@ void Script::parse() parsed = true; - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); MemoryManager::GCBlocker gcBlocker(v4->memoryManager); @@ -285,7 +281,7 @@ ReturnedValue Script::run() if (!vmFunction) return Encode::undefined(); - QV4::ExecutionEngine *engine = scope->engine; + QV4::ExecutionEngine *engine = scope->engine(); QV4::Scope valueScope(engine); if (qml.isUndefined()) { @@ -293,15 +289,14 @@ ReturnedValue Script::run() ExecutionContextSaver ctxSaver(valueScope, scope); ContextStateSaver stateSaver(valueScope, scope); - scope->strictMode = vmFunction->isStrict(); - scope->lookups = vmFunction->compilationUnit->runtimeLookups; - scope->compilationUnit = vmFunction->compilationUnit; + scope->d()->strictMode = vmFunction->isStrict(); + scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups; + scope->d()->compilationUnit = vmFunction->compilationUnit; return vmFunction->code(engine, vmFunction->codeData); } else { - ScopedObject qmlObj(valueScope, qml.value()); - ScopedContext ctx(valueScope, scope); - ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(ctx, vmFunction, qmlObj)); + Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); + ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); return f->call(callData); @@ -376,11 +371,10 @@ ReturnedValue Script::qmlBinding() { if (!parsed) parse(); - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - ScopedObject qmlObj(valueScope, qml.value()); - ScopedContext ctx(valueScope, scope); - ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(ctx, vmFunction, qmlObj)); + Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value()); + ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); return v.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 05a9e45f45..015bfff56a 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -87,11 +87,10 @@ struct ContextStateSaver { namespace Heap { struct QmlBindingWrapper : Heap::FunctionObject { - QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::Object *qml); + QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml); // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! - QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::Object *qml); - Object *qml; - CallContext *qmlContext; + QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml); + Pointer<Object> qml; }; } @@ -99,21 +98,19 @@ struct QmlBindingWrapper : Heap::FunctionObject { struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { V4_OBJECT2(QmlBindingWrapper, FunctionObject) - static ReturnedValue call(Managed *that, CallData *); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *m, ExecutionEngine *e); - Heap::CallContext *context() const { return d()->qmlContext; } + Heap::QmlContext *context() const { return static_cast<Heap::QmlContext *>(d()->scope.ptr); } static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - -private: }; struct Q_QML_EXPORT Script { Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) - , scope(scope->d()), strictMode(false), inheritContext(false), parsed(false) + , scope(scope), strictMode(false), inheritContext(false), parsed(false) , vmFunction(0), parseAsBinding(false) {} Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) @@ -125,8 +122,7 @@ struct Q_QML_EXPORT Script { int line; int column; QString sourceCode; - // ### GC - Heap::ExecutionContext *scope; + ExecutionContext *scope; bool strictMode; bool inheritContext; bool parsed; diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index f1f546bece..4fba65d396 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -175,7 +175,7 @@ template <> QUrl convertValueToElement(const Value &value) template <> QModelIndex convertValueToElement(const Value &value) { - const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value); + const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>(); if (v) return v->toVariant().toModelIndex(); return QModelIndex(); @@ -183,7 +183,7 @@ template <> QModelIndex convertValueToElement(const Value &value) template <> QItemSelectionRange convertValueToElement(const Value &value) { - const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value); + const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>(); if (v) return v->toVariant().value<QItemSelectionRange>(); return QItemSelectionRange(); @@ -231,7 +231,7 @@ public: defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length); } - QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) + QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const { /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { @@ -400,7 +400,7 @@ public: ScopedCallData callData(scope, 2); callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs); callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs); - callData->thisObject = this->m_ctx->d()->engine->globalObject(); + callData->thisObject = this->m_ctx->d()->engine->globalObject; QV4::ScopedValue result(scope, compare->call(callData)); return result->toNumber() < 0; } @@ -419,7 +419,7 @@ public: } QV4::Scope scope(ctx); - if (ctx->argc() == 1 && ctx->args()[0].asFunctionObject()) { + if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) { CompareFunctor cf(ctx, ctx->args()[0]); std::sort(d()->container.begin(), d()->container.end(), cf); } else { @@ -526,8 +526,8 @@ public: QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); } - static QV4::ReturnedValue getIndexed(QV4::Managed *that, uint index, bool *hasProperty) - { return static_cast<QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } + static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty) + { return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } static void putIndexed(Managed *that, uint index, const QV4::Value &value) { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); } static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) @@ -544,7 +544,7 @@ public: template <typename Container> Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : Heap::Object(engine->emptyClass, engine->sequencePrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->sequencePrototype()) , container(container) , propertyIndex(-1) , isReference(false) @@ -557,7 +557,7 @@ Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, const template <typename Container> Heap::QQmlSequence<Container>::QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) - : Heap::Object(engine->emptyClass, engine->sequencePrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->sequencePrototype()) , object(object) , propertyIndex(propertyIndex) , isReference(true) @@ -605,7 +605,7 @@ void SequencePrototype::init() { FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE) defineDefaultProperty(QStringLiteral("sort"), method_sort, 1); - defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); + defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0); } #undef REGISTER_QML_SEQUENCE_METATYPE @@ -700,11 +700,11 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo { *succeeded = true; - if (!array.asArrayObject()) { + if (!array.as<ArrayObject>()) { *succeeded = false; return QVariant(); } - QV4::Scope scope(array.asObject()->engine()); + QV4::Scope scope(array.as<Object>()->engine()); QV4::ScopedArrayObject a(scope, array); FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); } @@ -717,7 +717,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo return qMetaTypeId<SequenceType>(); \ } else -int SequencePrototype::metaTypeForSequence(QV4::Object *object) +int SequencePrototype::metaTypeForSequence(const QV4::Object *object) { FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE) /*else*/ { diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 9949278a89..560c3c27ca 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -48,9 +48,10 @@ #include <QtCore/qglobal.h> #include <QtCore/qvariant.h> -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4object_p.h" #include "qv4context_p.h" +#include "qv4string_p.h" QT_BEGIN_NAMESPACE @@ -70,7 +71,7 @@ struct SequencePrototype : public QV4::Object static bool isSequenceType(int sequenceTypeId); static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded); - static int metaTypeForSequence(Object *object); + static int metaTypeForSequence(const Object *object); static QVariant toVariant(Object *object); static QVariant toVariant(const Value &array, int typeHint, bool *succeeded); }; diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp index e669924d4a..090e9c7e6a 100644 --- a/src/qml/jsruntime/qv4serialize.cpp +++ b/src/qml/jsruntime/qv4serialize.cpp @@ -37,7 +37,7 @@ #include <private/qqmllistmodel_p.h> #include <private/qqmllistmodelworkeragent_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4regexpobject_p.h> #include <private/qv4sequenceobject_p.h> @@ -168,11 +168,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine char *buffer = data.data() + offset; memcpy(buffer, qstr.constData(), length*sizeof(QChar)); - } else if (v.asFunctionObject()) { + } else if (v.as<FunctionObject>()) { // XXX TODO: Implement passing function objects between the main and // worker scripts push(data, valueheader(WorkerUndefined)); - } else if (QV4::ArrayObject *array = v.asArrayObject()) { + } else if (const QV4::ArrayObject *array = v.as<ArrayObject>()) { uint length = array->getLength(); if (length > 0xFFFFFF) { push(data, valueheader(WorkerUndefined)); @@ -195,11 +195,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerNumber)); push(data, v.asDouble()); - } else if (QV4::DateObject *d = v.asDateObject()) { + } else if (const QV4::DateObject *d = v.as<DateObject>()) { reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerDate)); - push(data, d->date().asDouble()); - } else if (RegExpObject *re = v.as<RegExpObject>()) { + push(data, d->date()); + } else if (const RegExpObject *re = v.as<RegExpObject>()) { quint32 flags = re->flags(); QString pattern = re->source(); int length = pattern.length() + 1; @@ -218,7 +218,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine char *buffer = data.data() + offset; memcpy(buffer, pattern.constData(), length*sizeof(QChar)); - } else if (QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { + } else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { // XXX TODO: Generalize passing objects between the main thread and worker scripts so // that others can trivially plug in their elements. QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object()); @@ -231,10 +231,10 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine } // No other QObject's are allowed to be sent push(data, valueheader(WorkerUndefined)); - } else if (Object *o = v.asObject()) { + } else if (const Object *o = v.as<Object>()) { if (o->isListType()) { // valid sequence. we generate a length (sequence length + 1 for the sequence type) - uint seqLength = ScopedValue(scope, o->get(engine->id_length))->toUInt32(); + uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32(); uint length = seqLength + 1; if (length > 0xFFFFFF) { push(data, valueheader(WorkerUndefined)); @@ -265,7 +265,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine s = properties->getIndexed(ii); serialize(data, s, engine); - QV4::String *str = s->asString(); + QV4::String *str = s->as<String>(); val = o->get(str); if (scope.hasException()) scope.engine->catchException(); @@ -356,7 +356,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine) QVariant var = qVariantFromValue(ref); QV4::ScopedValue v(scope, scope.engine->fromVariant(var)); QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref"))); - rv->asObject()->defineReadonlyProperty(s, v); + rv->as<Object>()->defineReadonlyProperty(s, v); agent->release(); agent->setEngine(engine); diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/jsruntime/qv4serialize_p.h index 06eaffe4c4..d5d48edee7 100644 --- a/src/qml/jsruntime/qv4serialize_p.h +++ b/src/qml/jsruntime/qv4serialize_p.h @@ -46,7 +46,7 @@ // #include <QtCore/qbytearray.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h index 861c7dd28d..8496fc32e7 100644 --- a/src/qml/jsruntime/qv4sparsearray_p.h +++ b/src/qml/jsruntime/qv4sparsearray_p.h @@ -35,11 +35,7 @@ #define QV4SPARSEARRAY_H #include "qv4global_p.h" -#include <QtCore/qmap.h> -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" -#include "qv4property_p.h" -#include <assert.h> +#include <QtCore/qlist.h> //#define Q_MAP_DEBUG #ifdef Q_MAP_DEBUG @@ -188,7 +184,7 @@ public: typedef qptrdiff difference_type; typedef int size_type; -#ifndef QT_NO_DEBUG +#ifdef Q_MAP_DEBUG void dump() const; #endif }; @@ -261,7 +257,7 @@ inline void SparseArray::push_back(uint index, uint len) n->value = index; } -#ifndef QT_NO_DEBUG +#ifdef Q_MAP_DEBUG inline void SparseArray::dump() const { const SparseArrayNode *it = begin(); @@ -344,4 +340,4 @@ inline SparseArrayNode *SparseArray::upperBound(uint akey) QT_END_NAMESPACE -#endif // QMAP_H +#endif diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 20dd84420c..cf013121b1 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4string_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #ifndef V4_BOOTSTRAP #include "qv4identifiertable_p.h" #include "qv4runtime_p.h" diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 5a0c83b4b9..b133f68b20 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -184,6 +184,20 @@ public: static uint toArrayIndex(const QString &str); }; +template<> +inline const String *Value::as() const { + return isManaged() && m && m->vtable->isString ? static_cast<const String *>(this) : 0; +} + +#ifndef V4_BOOTSTRAP +template<> +inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) +{ + return v.toString(e)->asReturnedValue(); +} +#endif + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index e0b84f6da3..402ab420fc 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -36,7 +36,7 @@ #include "qv4regexp_p.h" #include "qv4regexpobject_p.h" #include "qv4objectproto_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4alloca_p.h" #include <QtCore/QDateTime> @@ -71,43 +71,44 @@ Heap::StringObject::StringObject(InternalClass *ic, QV4::Object *prototype) : Heap::Object(ic, prototype) { Q_ASSERT(vtable == QV4::StringObject::staticVTable()); - value = ic->engine->newString()->asReturnedValue(); - tmpProperty.value = Primitive::undefinedValue(); + string = ic->engine->newString(); Scope scope(ic->engine); ScopedObject s(scope, this); - s->defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0)); + s->defineReadonlyProperty(ic->engine->id_length(), Primitive::fromInt32(0)); } -Heap::StringObject::StringObject(ExecutionEngine *engine, const Value &val) - : Heap::Object(engine->emptyClass, engine->stringPrototype.asObject()) +Heap::StringObject::StringObject(ExecutionEngine *engine, const QV4::String *str) + : Heap::Object(engine->emptyClass, engine->stringPrototype()) { - value = val; - Q_ASSERT(value.isString()); - tmpProperty.value = Primitive::undefinedValue(); + string = str->d(); Scope scope(engine); ScopedObject s(scope, this); - s->defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length())); + s->defineReadonlyProperty(engine->id_length(), Primitive::fromUInt32(length())); } -Property *Heap::StringObject::getIndex(uint index) const +Heap::String *Heap::StringObject::getIndex(uint index) const { - QString str = value.stringValue()->toQString(); + QString str = string->toQString(); if (index >= (uint)str.length()) return 0; - tmpProperty.value = Encode(internalClass->engine->newString(str.mid(index, 1))); - return &tmpProperty; + return internalClass->engine->newString(str.mid(index, 1)); +} + +uint Heap::StringObject::length() const +{ + return string->toQString().length(); } bool StringObject::deleteIndexedProperty(Managed *m, uint index) { ExecutionEngine *v4 = static_cast<StringObject *>(m)->engine(); Scope scope(v4); - Scoped<StringObject> o(scope, m->asStringObject()); + Scoped<StringObject> o(scope, m->as<StringObject>()); Q_ASSERT(!!o); - if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) { + if (index < static_cast<uint>(o->d()->string->toQString().length())) { if (v4->currentContext()->strictMode) v4->throwTypeError(); return false; @@ -119,16 +120,17 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Heap::String { *name = (Heap::String *)0; StringObject *s = static_cast<StringObject *>(m); - uint slen = s->d()->value.stringValue()->toQString().length(); + uint slen = s->d()->string->toQString().length(); if (it->arrayIndex <= slen) { while (it->arrayIndex < slen) { *index = it->arrayIndex; ++it->arrayIndex; PropertyAttributes a; - Property *pd = s->__getOwnProperty__(*index, &a); + Property pd; + s->getOwnProperty(*index, &a, &pd); if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { *attrs = a; - p->copy(pd, a); + p->copy(&pd, a); return; } } @@ -146,8 +148,7 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Heap::String void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e) { StringObject::Data *o = static_cast<StringObject::Data *>(that); - o->value.stringValue()->mark(e); - o->tmpProperty.value.mark(e); + o->string->mark(e); Object::markObjects(that, e); } @@ -158,11 +159,11 @@ Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope) { } -ReturnedValue StringCtor::construct(Managed *m, CallData *callData) +ReturnedValue StringCtor::construct(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); - ScopedValue value(scope); + ScopedString value(scope); if (callData->argc) value = callData->args[0].toString(v4); else @@ -170,9 +171,9 @@ ReturnedValue StringCtor::construct(Managed *m, CallData *callData) return Encode(v4->newStringObject(value)); } -ReturnedValue StringCtor::call(Managed *m, CallData *callData) +ReturnedValue StringCtor::call(const Managed *m, CallData *callData) { - ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); + ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); Scope scope(v4); ScopedValue value(scope); if (callData->argc) @@ -187,13 +188,13 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("fromCharCode"), method_fromCharCode, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString, method_toString); - defineDefaultProperty(engine->id_valueOf, method_toString); // valueOf and toString are identical + defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_valueOf(), method_toString); // valueOf and toString are identical defineDefaultProperty(QStringLiteral("charAt"), method_charAt, 1); defineDefaultProperty(QStringLiteral("charCodeAt"), method_charCodeAt, 1); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); @@ -220,8 +221,8 @@ static QString getThisString(ExecutionContext *ctx) ScopedValue t(scope, ctx->thisObject()); if (t->isString()) return t->stringValue()->toQString(); - if (StringObject *thisString = t->asStringObject()) - return thisString->d()->value.stringValue()->toQString(); + if (StringObject *thisString = t->as<StringObject>()) + return thisString->d()->string->toQString(); if (t->isUndefined() || t->isNull()) { scope.engine->throwTypeError(); return QString(); @@ -234,10 +235,10 @@ ReturnedValue StringPrototype::method_toString(CallContext *context) if (context->thisObject().isString()) return context->thisObject().asReturnedValue(); - StringObject *o = context->thisObject().asStringObject(); + StringObject *o = context->thisObject().as<StringObject>(); if (!o) return context->engine()->throwTypeError(); - return o->d()->value.asReturnedValue(); + return Encode(o->d()->string); } ReturnedValue StringPrototype::method_charAt(CallContext *context) @@ -368,7 +369,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!rx) { ScopedCallData callData(scope, 1); callData->args[0] = regexp; - rx = context->d()->engine->regExpCtor.asFunctionObject()->construct(callData); + rx = context->d()->engine->regExpCtor()->construct(callData); } if (!rx) @@ -379,7 +380,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) // ### use the standard builtin function, not the one that might be redefined in the proto ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec"))); - ScopedFunctionObject exec(scope, scope.engine->regExpPrototype.asObject()->get(execString)); + ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString)); ScopedCallData callData(scope, 1); callData->thisObject = rx; @@ -470,8 +471,8 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) { Scope scope(ctx); QString string; - if (StringObject *thisString = ctx->thisObject().asStringObject()) - string = thisString->d()->value.stringValue()->toQString(); + if (StringObject *thisString = ctx->thisObject().as<StringObject>()) + string = thisString->d()->string->toQString(); else string = ctx->thisObject().toQString(); @@ -481,12 +482,12 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) uint allocatedMatchOffsets = 64; uint _matchOffsets[64]; uint *matchOffsets = _matchOffsets; - uint nMatchOffsets = 0; ScopedValue searchValue(scope, ctx->argument(0)); Scoped<RegExpObject> regExp(scope, searchValue); if (regExp) { uint offset = 0; + uint nMatchOffsets = 0; // We extract the pointer here to work around a compiler bug on Android. Scoped<RegExp> re(scope, regExp->value()); @@ -519,7 +520,6 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) int idx = string.indexOf(searchString); if (idx != -1) { numStringMatches = 1; - nMatchOffsets = 2; matchOffsets[0] = idx; matchOffsets[1] = idx + searchString.length(); } @@ -593,7 +593,7 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) if (!regExp) { ScopedCallData callData(scope, 1); callData->args[0] = regExpValue; - regExpValue = ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData); + regExpValue = ctx->d()->engine->regExpCtor()->construct(callData); if (scope.engine->hasException) return Encode::undefined(); regExp = regExpValue->as<RegExpObject>(); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 459dc1322e..709b73f0bb 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -45,12 +45,11 @@ namespace Heap { struct StringObject : Object { StringObject(InternalClass *ic, QV4::Object *prototype); - StringObject(ExecutionEngine *engine, const Value &value); - Value value; + StringObject(ExecutionEngine *engine, const QV4::String *string); + String *string; - Property *getIndex(uint index) const; - // ### get rid of tmpProperty - mutable Property tmpProperty; + Heap::String *getIndex(uint index) const; + uint length() const; }; struct StringCtor : FunctionObject { @@ -63,9 +62,12 @@ struct StringObject: Object { V4_OBJECT2(StringObject, Object) Q_MANAGED_TYPE(StringObject) - Property *getIndex(uint index) const { + Heap::String *getIndex(uint index) const { return d()->getIndex(index); } + uint length() const { + return d()->length(); + } static bool deleteIndexedProperty(Managed *m, uint index); @@ -78,8 +80,8 @@ struct StringCtor: FunctionObject { V4_OBJECT2(StringCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; struct StringPrototype: StringObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 429ec96f0b..f5b81fb6f7 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4typedarray_p.h" #include "qv4arraybuffer_p.h" +#include "qv4string_p.h" #include <cmath> @@ -201,10 +202,10 @@ Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::T { } -ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) +ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) { - Scope scope(static_cast<Object *>(m)->engine()); - Scoped<TypedArrayCtor> that(scope, static_cast<TypedArrayCtor *>(m)); + Scope scope(static_cast<const Object *>(m)->engine()); + Scoped<TypedArrayCtor> that(scope, static_cast<const TypedArrayCtor *>(m)); if (!callData->argc || !callData->args[0].isObject()) { // ECMA 6 22.2.1.1 @@ -299,7 +300,7 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) // ECMA 6 22.2.1.3 ScopedObject o(scope, callData->argument(0)); - uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length))->toInteger(), (double)UINT_MAX); + uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX); if (scope.engine->hasException) return scope.engine->throwTypeError(); @@ -329,13 +330,13 @@ ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) return array.asReturnedValue(); } -ReturnedValue TypedArrayCtor::call(Managed *that, CallData *callData) +ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData) { return construct(that, callData); } Heap::TypedArray::TypedArray(ExecutionEngine *e, Type t) - : Heap::Object(e->emptyClass, e->typedArrayPrototype[t].asObject()), + : Heap::Object(e->emptyClass, e->typedArrayPrototype + t), type(operations + t), arrayType(t) { @@ -347,10 +348,10 @@ void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } -ReturnedValue TypedArray::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty) { - Scope scope(static_cast<Object *>(m)->engine()); - Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + Scope scope(static_cast<const Object *>(m)->engine()); + Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); uint bytesPerElement = a->d()->type->bytesPerElement; uint byteOffset = a->d()->byteOffset + index * bytesPerElement; @@ -390,10 +391,10 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); - ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); - defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); @@ -470,7 +471,7 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) if (scope.engine->hasException || !o) return scope.engine->throwTypeError(); - double len = ScopedValue(scope, o->get(scope.engine->id_length))->toNumber(); + double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber(); uint l = (uint)len; if (scope.engine->hasException || l != len) return scope.engine->throwTypeError(); @@ -563,7 +564,7 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) int newLen = end - begin; - ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor)); + ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index afd1bb97e7..8e1090dcd2 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -72,7 +72,7 @@ struct TypedArray : Object { TypedArray(ExecutionEngine *e, Type t); const TypedArrayOperations *type; - ArrayBuffer *buffer; + Pointer<ArrayBuffer> buffer; uint byteLength; uint byteOffset; Type arrayType; @@ -113,7 +113,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object } static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void putIndexed(Managed *m, uint index, const Value &value); }; @@ -121,8 +121,8 @@ struct TypedArrayCtor: FunctionObject { V4_OBJECT2(TypedArrayCtor, FunctionObject) - static ReturnedValue construct(Managed *m, CallData *callData); - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue construct(const Managed *m, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 68228f06bb..d659d02c3b 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -32,10 +32,11 @@ ****************************************************************************/ #include <qv4engine_p.h> #include <qv4runtime_p.h> +#include <qv4string_p.h> #ifndef V4_BOOTSTRAP #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #endif #include <wtf/MathExtras.h> @@ -68,6 +69,28 @@ int Value::toUInt16() const return (unsigned short)number; } +bool Value::toBoolean() const +{ + switch (type()) { + case Value::Undefined_Type: + case Value::Null_Type: + return false; + case Value::Boolean_Type: + case Value::Integer_Type: + return (bool)int_32; + case Value::Managed_Type: +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else + if (isString()) + return stringValue()->toQString().length() > 0; +#endif + return true; + default: // double + return doubleValue() && !std::isnan(doubleValue()); + } +} + double Value::toInteger() const { if (integerCompatible()) @@ -87,10 +110,10 @@ double Value::toNumberImpl() const #else if (isString()) return RuntimeHelpers::stringToNumber(stringValue()->toQString()); - { - Q_ASSERT(isObject()); - Scope scope(objectValue()->engine()); - ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT)); + { + Q_ASSERT(isObject()); + Scope scope(objectValue()->engine()); + ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT)); if (scope.engine->hasException) return 0; return prim->toNumber(); @@ -281,4 +304,35 @@ Heap::Object *Value::toObject(ExecutionEngine *e) const return RuntimeHelpers::convertToObject(e, *this); } +uint Value::asArrayLength(bool *ok) const +{ + *ok = true; + if (isInteger()) { + if (int_32 >= 0) { + return (uint)int_32; + } else { + *ok = false; + return UINT_MAX; + } + } + if (isNumber()) { + double d = doubleValue(); + uint idx = (uint)d; + if (idx != d) { + *ok = false; + return UINT_MAX; + } + return idx; + } + if (isString()) + return stringValue()->toUInt(ok); + + uint idx = toUInt32(); + double d = toNumber(); + if (d != idx) { + *ok = false; + return UINT_MAX; + } + return idx; +} #endif // V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h deleted file mode 100644 index 3a4c5c4822..0000000000 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ /dev/null @@ -1,293 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QV4VALUE_INL_H -#define QV4VALUE_INL_H - -#include <cmath> // this HAS to come - -#include "qv4value_p.h" - -#include "qv4string_p.h" -#include "qv4managed_p.h" -#include "qv4engine_p.h" - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -inline bool Value::isString() const -{ - if (!isManaged()) - return false; - return m && m->vtable->isString; -} -inline bool Value::isObject() const -{ - if (!isManaged()) - return false; - return m && m->vtable->isObject; -} - -inline bool Value::isPrimitive() const -{ - return !isObject(); -} - -inline String *Value::asString() const -{ - if (isString()) - return stringValue(); - return 0; -} - -inline void Value::mark(ExecutionEngine *e) const -{ - if (!val) - return; - Managed *m = asManaged(); - if (m) - m->mark(e); -} - -inline Primitive Primitive::nullValue() -{ - Primitive v; -#if QT_POINTER_SIZE == 8 - v.val = quint64(_Null_Type) << Tag_Shift; -#else - v.tag = _Null_Type; - v.int_32 = 0; -#endif - return v; -} - -inline Primitive Primitive::fromBoolean(bool b) -{ - Primitive v; - v.tag = _Boolean_Type; - v.int_32 = (bool)b; - return v; -} - -inline Primitive Primitive::fromDouble(double d) -{ - Primitive v; - v.setDouble(d); - return v; -} - -inline Primitive Primitive::fromInt32(int i) -{ - Primitive v; - v.tag = _Integer_Type; - v.int_32 = i; - return v; -} - -inline Primitive Primitive::fromUInt32(uint i) -{ - Primitive v; - if (i < INT_MAX) { - v.tag = _Integer_Type; - v.int_32 = (int)i; - } else { - v.setDouble(i); - } - return v; -} - -inline double Value::toNumber() const -{ - if (isInteger()) - return int_32; - if (isDouble()) - return doubleValue(); - return toNumberImpl(); -} - -inline int Value::toInt32() const -{ - if (isInteger()) - return int_32; - double d = isNumber() ? doubleValue() : toNumberImpl(); - - const double D32 = 4294967296.0; - const double D31 = D32 / 2.0; - - if ((d >= -D31 && d < D31)) - return static_cast<int>(d); - - return Primitive::toInt32(d); -} - -inline unsigned int Value::toUInt32() const -{ - return (unsigned int)toInt32(); -} - - -inline bool Value::toBoolean() const -{ - switch (type()) { - case Value::Undefined_Type: - case Value::Null_Type: - return false; - case Value::Boolean_Type: - case Value::Integer_Type: - return (bool)int_32; - case Value::Managed_Type: -#ifdef V4_BOOTSTRAP - Q_UNIMPLEMENTED(); -#else - if (isString()) - return stringValue()->toQString().length() > 0; -#endif - return true; - default: // double - return doubleValue() && !std::isnan(doubleValue()); - } -} - -#ifndef V4_BOOTSTRAP -inline uint Value::asArrayIndex() const -{ -#if QT_POINTER_SIZE == 8 - if (!isNumber()) - return UINT_MAX; - if (isInteger()) - return int_32 >= 0 ? (uint)int_32 : UINT_MAX; -#else - if (isInteger() && int_32 >= 0) - return (uint)int_32; - if (!isDouble()) - return UINT_MAX; -#endif - double d = doubleValue(); - uint idx = (uint)d; - if (idx != d) - return UINT_MAX; - return idx; -} - -inline uint Value::asArrayLength(bool *ok) const -{ - *ok = true; - if (isInteger()) { - if (int_32 >= 0) { - return (uint)int_32; - } else { - *ok = false; - return UINT_MAX; - } - } - if (isNumber()) { - double d = doubleValue(); - uint idx = (uint)d; - if (idx != d) { - *ok = false; - return UINT_MAX; - } - return idx; - } - if (isString()) - return stringValue()->toUInt(ok); - - uint idx = toUInt32(); - double d = toNumber(); - if (d != idx) { - *ok = false; - return UINT_MAX; - } - return idx; -} - -inline Object *Value::asObject() const -{ - return isObject() ? objectValue() : 0; -} - -inline FunctionObject *Value::asFunctionObject() const -{ - return isObject() ? managed()->asFunctionObject() : 0; -} - -inline NumberObject *Value::asNumberObject() const -{ - return isObject() ? managed()->asNumberObject() : 0; -} - -inline StringObject *Value::asStringObject() const -{ - return isObject() ? managed()->asStringObject() : 0; -} - -inline DateObject *Value::asDateObject() const -{ - return isObject() ? managed()->asDateObject() : 0; -} - -inline ArrayObject *Value::asArrayObject() const -{ - return isObject() ? managed()->asArrayObject() : 0; -} - -inline ErrorObject *Value::asErrorObject() const -{ - return isObject() ? managed()->asErrorObject() : 0; -} - -template<typename T> -inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; } - -#ifndef V4_BOOTSTRAP - -template<> -inline String *value_cast(const Value &v) { - return v.asString(); -} - -template<> -inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) -{ - return v.toString(e)->asReturnedValue(); -} - -#endif - -#endif - -} // namespace QV4 - -QT_END_NAMESPACE - -#endif diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index cd1aef86d7..7454cbfff4 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -37,61 +37,18 @@ #include <QtCore/QString> #include "qv4global_p.h" +#include <private/qv4heap_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -typedef uint Bool; - namespace Heap { - -struct Q_QML_EXPORT Base { - union { - const ManagedVTable *vtable; - quintptr mm_data; - }; - - inline ReturnedValue asReturnedValue() const; - inline void mark(QV4::ExecutionEngine *engine); - - enum { - MarkBit = 0x1, - NotInUse = 0x2, - PointerMask = ~0x3 - }; - - ManagedVTable *gcGetVtable() const { - return reinterpret_cast<ManagedVTable *>(mm_data & PointerMask); - } - inline bool isMarked() const { - return mm_data & MarkBit; - } - inline void setMarkBit() { - mm_data |= MarkBit; - } - inline void clearMarkBit() { - mm_data &= ~MarkBit; - } - - inline bool inUse() const { - return !(mm_data & NotInUse); - } - - Base *nextFree() { - return reinterpret_cast<Base *>(mm_data & PointerMask); - } - void setNextFree(Base *m) { - mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); - } - - void *operator new(size_t, Managed *m) { return m; } - void *operator new(size_t, Heap::Base *m) { return m; } - void operator delete(void *, Heap::Base *) {} -}; - + struct Base; } +typedef uint Bool; + struct Q_QML_PRIVATE_EXPORT Value { /* @@ -326,13 +283,11 @@ struct Q_QML_PRIVATE_EXPORT Value return v; } - static inline Value fromManaged(Managed *m); - int toUInt16() const; inline int toInt32() const; inline unsigned int toUInt32() const; - inline bool toBoolean() const; + bool toBoolean() const; double toInteger() const; inline double toNumber() const; double toNumberImpl() const; @@ -349,17 +304,28 @@ struct Q_QML_PRIVATE_EXPORT Value return b; } - inline String *asString() const; - inline Managed *asManaged() const; - inline Object *asObject() const; - inline FunctionObject *asFunctionObject() const; - inline NumberObject *asNumberObject() const; - inline StringObject *asStringObject() const; - inline DateObject *asDateObject() const; - inline ArrayObject *asArrayObject() const; - inline ErrorObject *asErrorObject() const; + template <typename T> + const T *as() const { + if (!m || !isManaged()) + return 0; + + Q_ASSERT(m->vtable); +#if !defined(QT_NO_QOBJECT_CHECK) + static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this)); +#endif + const VTable *vt = m->vtable; + while (vt) { + if (vt == T::staticVTable()) + return static_cast<const T *>(this); + vt = vt->parent; + } + return 0; + } + template <typename T> + T *as() { + return const_cast<T *>(const_cast<const Value *>(this)->as<T>()); + } - template<typename T> inline T *as() const; template<typename T> inline T *cast() { return static_cast<T *>(managed()); } @@ -368,7 +334,9 @@ struct Q_QML_PRIVATE_EXPORT Value } inline uint asArrayIndex() const; - inline uint asArrayLength(bool *ok) const; +#ifndef V4_BOOTSTRAP + uint asArrayLength(bool *ok) const; +#endif ReturnedValue asReturnedValue() const { return val; } static Value fromReturnedValue(ReturnedValue val) { Value v; v.val = val; return v; } @@ -376,12 +344,17 @@ struct Q_QML_PRIVATE_EXPORT Value // Section 9.12 bool sameValue(Value other) const; - inline void mark(ExecutionEngine *e) const; + inline void mark(ExecutionEngine *e); Value &operator =(const ScopedValue &v); Value &operator=(ReturnedValue v) { val = v; return *this; } Value &operator=(Managed *m) { - val = Value::fromManaged(m).val; + if (!m) { + tag = Undefined_Type; + uint_32 = 0; + } else { + val = reinterpret_cast<Value *>(m)->val; + } return *this; } Value &operator=(Heap::Base *o) { @@ -400,13 +373,64 @@ struct Q_QML_PRIVATE_EXPORT Value } }; -inline Managed *Value::asManaged() const +inline bool Value::isString() const +{ + if (!isManaged()) + return false; + return m && m->vtable->isString; +} +inline bool Value::isObject() const +{ + if (!isManaged()) + return false; + return m && m->vtable->isObject; +} + +inline bool Value::isPrimitive() const +{ + return !isObject(); +} + +inline double Value::toNumber() const +{ + if (isInteger()) + return int_32; + if (isDouble()) + return doubleValue(); + return toNumberImpl(); +} + + +#ifndef V4_BOOTSTRAP +inline uint Value::asArrayIndex() const +{ +#if QT_POINTER_SIZE == 8 + if (!isNumber()) + return UINT_MAX; + if (isInteger()) + return int_32 >= 0 ? (uint)int_32 : UINT_MAX; +#else + if (isInteger() && int_32 >= 0) + return (uint)int_32; + if (!isDouble()) + return UINT_MAX; +#endif + double d = doubleValue(); + uint idx = (uint)d; + if (idx != d) + return UINT_MAX; + return idx; +} +#endif + +inline +ReturnedValue Heap::Base::asReturnedValue() const { - if (isManaged()) - return managed(); - return 0; + return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue(); } + + struct Q_QML_PRIVATE_EXPORT Primitive : public Value { inline static Primitive emptyValue(); @@ -445,34 +469,52 @@ inline Primitive Primitive::emptyValue() return v; } -template <typename T> -struct TypedValue : public Value +inline Primitive Primitive::nullValue() { - template<typename X> - TypedValue &operator =(X *x) { - m = x; -#if QT_POINTER_SIZE == 4 - tag = Managed_Type; + Primitive v; +#if QT_POINTER_SIZE == 8 + v.val = quint64(_Null_Type) << Tag_Shift; +#else + v.tag = _Null_Type; + v.int_32 = 0; #endif - return *this; - } - TypedValue &operator =(T *t); - TypedValue &operator =(const Scoped<T> &v); -// TypedValue &operator =(const ManagedRef<T> &v); - - TypedValue &operator =(const TypedValue<T> &t); + return v; +} - bool operator!() const { return !managed(); } +inline Primitive Primitive::fromBoolean(bool b) +{ + Primitive v; + v.tag = _Boolean_Type; + v.int_32 = (bool)b; + return v; +} - operator T *() { return static_cast<T *>(managed()); } - T *operator->() { return static_cast<T *>(managed()); } - const T *operator->() const { return static_cast<T *>(managed()); } - T *getPointer() const { return static_cast<T *>(managed()); } +inline Primitive Primitive::fromDouble(double d) +{ + Primitive v; + v.setDouble(d); + return v; +} - void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); } -}; -typedef TypedValue<String> StringValue; +inline Primitive Primitive::fromInt32(int i) +{ + Primitive v; + v.tag = _Integer_Type; + v.int_32 = i; + return v; +} +inline Primitive Primitive::fromUInt32(uint i) +{ + Primitive v; + if (i < INT_MAX) { + v.tag = _Integer_Type; + v.int_32 = (int)i; + } else { + v.setDouble(i); + } + return v; +} struct Encode { static ReturnedValue undefined() { @@ -519,21 +561,29 @@ private: Encode(void *); }; -inline -ReturnedValue Heap::Base::asReturnedValue() const +template<typename T> +ReturnedValue value_convert(ExecutionEngine *e, const Value &v); + +inline int Value::toInt32() const { - return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue(); -} + if (isInteger()) + return int_32; + double d = isNumber() ? doubleValue() : toNumberImpl(); + const double D32 = 4294967296.0; + const double D31 = D32 / 2.0; -template<typename T> -T *value_cast(const Value &v) + if ((d >= -D31 && d < D31)) + return static_cast<int>(d); + + return Primitive::toInt32(d); +} + +inline unsigned int Value::toUInt32() const { - return v.as<T>(); + return (unsigned int)toInt32(); } -template<typename T> -ReturnedValue value_convert(ExecutionEngine *e, const Value &v); } diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 966f83acef..c919d24461 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -44,7 +44,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(VariantObject); Heap::VariantObject::VariantObject(QV4::ExecutionEngine *engine, const QVariant &value) - : Heap::Object(engine->emptyClass, engine->variantPrototype.asObject()) + : Heap::Object(engine->emptyClass, engine->variantPrototype()) { data = value; if (isScarce()) @@ -96,8 +96,8 @@ void VariantPrototype::init() { defineDefaultProperty(QStringLiteral("preserve"), method_preserve, 0); defineDefaultProperty(QStringLiteral("destroy"), method_destroy, 0); - defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); - defineDefaultProperty(engine()->id_toString, method_toString, 0); + defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0); + defineDefaultProperty(engine()->id_toString(), method_toString, 0); } QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index 2b48412c4d..b19f12bb98 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -49,7 +49,7 @@ #include <QtQml/qqmllist.h> #include <QtCore/qvariant.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index dda5848f0b..761e377f75 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -37,13 +37,14 @@ #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4debugging_p.h> #include <private/qv4function_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4math_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4lookup_p.h> +#include <private/qv4string_p.h> #include <iostream> #include "qv4alloca_p.h" @@ -858,7 +859,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code engine->currentContext()->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) qt_v4CheckForBreak(context, scopes, scopeDepth); - MOTH_END_INSTR(Debug) + MOTH_END_INSTR(Line) MOTH_BEGIN_INSTR(LoadThis) VALUE(instr.result) = context->thisObject(); diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri new file mode 100644 index 0000000000..04b7566ccc --- /dev/null +++ b/src/qml/memory/memory.pri @@ -0,0 +1,14 @@ +INCLUDEPATH += $$PWD +INCLUDEPATH += $$OUT_PWD + +!qmldevtools_build { +SOURCES += \ + $$PWD/qv4mm.cpp \ + +HEADERS += \ + $$PWD/qv4mm_p.h + +} + +HEADERS += \ + $$PWD/qv4heap_p.h diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h new file mode 100644 index 0000000000..606fd47cbb --- /dev/null +++ b/src/qml/memory/qv4heap_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4HEAP_P_H +#define QV4HEAP_P_H + +#include <QtCore/QString> +#include <private/qv4global_p.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct VTable +{ + const VTable * const parent; + uint isExecutionContext : 1; + uint isString : 1; + uint isObject : 1; + uint isFunctionObject : 1; + uint isErrorObject : 1; + uint isArrayData : 1; + uint unused : 18; + uint type : 8; + const char *className; + void (*destroy)(Heap::Base *); + void (*markObjects)(Heap::Base *, ExecutionEngine *e); + bool (*isEqualTo)(Managed *m, Managed *other); +}; + +namespace Heap { + +struct Q_QML_EXPORT Base { + union { + const VTable *vtable; + quintptr mm_data; + }; + + inline ReturnedValue asReturnedValue() const; + inline void mark(QV4::ExecutionEngine *engine); + + enum { + MarkBit = 0x1, + NotInUse = 0x2, + PointerMask = ~0x3 + }; + + VTable *gcGetVtable() const { + return reinterpret_cast<VTable *>(mm_data & PointerMask); + } + inline bool isMarked() const { + return mm_data & MarkBit; + } + inline void setMarkBit() { + mm_data |= MarkBit; + } + inline void clearMarkBit() { + mm_data &= ~MarkBit; + } + + inline bool inUse() const { + return !(mm_data & NotInUse); + } + + Base *nextFree() { + return reinterpret_cast<Base *>(mm_data & PointerMask); + } + void setNextFree(Base *m) { + mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); + } + + void *operator new(size_t, Managed *m) { return m; } + void *operator new(size_t, Heap::Base *m) { return m; } + void operator delete(void *, Heap::Base *) {} +}; + +template <typename T> +struct Pointer { + Pointer() {} + Pointer(T *t) : ptr(t) {} + + T *operator->() const { return ptr; } + operator T *() const { return ptr; } + + Pointer &operator =(T *t) { ptr = t; return *this; } + + template <typename Type> + Type *cast() { return static_cast<Type *>(ptr); } + + T *ptr; +}; + +} + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index d5576b400a..7dbf12ff11 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -381,7 +381,7 @@ void MemoryManager::sweep(bool lastSweep) { if (m_weakValues) { for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { - if (Managed *m = (*it).asManaged()) { + if (Managed *m = (*it).as<Managed>()) { if (!m->markBit()) (*it) = Primitive::undefinedValue(); } @@ -525,7 +525,7 @@ void MemoryManager::runGC() size_t MemoryManager::getUsedMem() const { size_t usedMem = 0; - for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) { + for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) { Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base()); for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { Heap::Base *m = reinterpret_cast<Heap::Base *>(item); @@ -607,7 +607,7 @@ void MemoryManager::collectFromJSStack() const Value *v = m_d->engine->jsStackBase; Value *top = m_d->engine->jsStackTop; while (v < top) { - Managed *m = v->asManaged(); + Managed *m = v->as<Managed>(); if (m && m->inUse()) // Skip pointers to already freed objects, they are bogus as well m->mark(m_d->engine); diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 00b41b796a..422809ba54 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -34,9 +34,9 @@ #ifndef QV4GC_H #define QV4GC_H -#include "qv4global_p.h" -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" +#include <private/qv4global_p.h> +#include <private/qv4value_p.h> +#include <private/qv4scopedvalue_p.h> //#define DETAILED_MM_STATS diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 6e06fb42ef..d75262bf0b 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -8,6 +8,9 @@ win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS win32:!wince*:!winrt:LIBS += -lshell32 solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 +# Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT. +gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks + MODULE_PLUGIN_TYPES = \ qmltooling @@ -33,6 +36,7 @@ HEADERS += qtqmlglobal.h \ #modules include(util/util.pri) +include(memory/memory.pri) include(parser/parser.pri) include(compiler/compiler.pri) include(jsapi/jsapi.pri) diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index 59ed77b580..ba2ca43990 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -72,13 +72,16 @@ template<class T> class QQmlRefPointer { public: + enum Mode { + AddRef, + Adopt + }; inline QQmlRefPointer(); - inline QQmlRefPointer(T *); + inline QQmlRefPointer(T *, Mode m = AddRef); inline QQmlRefPointer(const QQmlRefPointer<T> &); inline ~QQmlRefPointer(); inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o); - inline QQmlRefPointer<T> &operator=(T *); inline bool isNull() const { return !o; } @@ -87,7 +90,7 @@ public: inline operator T*() const { return o; } inline T* data() const { return o; } - inline QQmlRefPointer<T> &take(T *); + inline QQmlRefPointer<T> &adopt(T *); private: T *o; @@ -133,10 +136,11 @@ QQmlRefPointer<T>::QQmlRefPointer() } template<class T> -QQmlRefPointer<T>::QQmlRefPointer(T *o) +QQmlRefPointer<T>::QQmlRefPointer(T *o, Mode m) : o(o) { - if (o) o->addref(); + if (m == AddRef && o) + o->addref(); } template<class T> @@ -161,21 +165,12 @@ QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other) return *this; } -template<class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(T *other) -{ - if (other) other->addref(); - if (o) o->release(); - o = other; - return *this; -} - /*! Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership of the callers reference of other. */ template<class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::take(T *other) +QQmlRefPointer<T> &QQmlRefPointer<T>::adopt(T *other) { if (o) o->release(); o = other; diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 4addcd9e58..62f6f76a7e 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -377,4 +377,31 @@ void QQmlThread::internalPostMethodToMain(Message *message) d->unlock(); } +void QQmlThread::waitForNextMessage() +{ + Q_ASSERT(!isThisThread()); + d->lock(); + Q_ASSERT(d->m_mainThreadWaiting == false); + + d->m_mainThreadWaiting = true; + + if (d->mainSync || !d->threadList.isEmpty()) { + if (d->mainSync) { + QQmlThread::Message *message = d->mainSync; + unlock(); + message->call(this); + delete message; + lock(); + d->mainSync = 0; + wakeOne(); + } else { + d->wait(); + } + } + + d->m_mainThreadWaiting = false; + d->unlock(); +} + + QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h index 86d7d2cf19..73658536ac 100644 --- a/src/qml/qml/ftw/qqmlthread_p.h +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -108,6 +108,8 @@ public: template<typename T, typename T2, class V, class V2, class O> inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + void waitForNextMessage(); + protected: virtual void startupThread(); virtual void shutdownThread(); diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index e733bcec05..10ae9f0e52 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -35,7 +35,6 @@ SOURCES += \ $$PWD/qqmlimport.cpp \ $$PWD/qqmllist.cpp \ $$PWD/qqmllocale.cpp \ - $$PWD/qqmlabstractexpression.cpp \ $$PWD/qqmljavascriptexpression.cpp \ $$PWD/qqmlabstractbinding.cpp \ $$PWD/qqmlvaluetypeproxybinding.cpp \ @@ -107,7 +106,6 @@ HEADERS += \ $$PWD/qqmlscriptstring_p.h \ $$PWD/qqmllocale_p.h \ $$PWD/qqmlcomponentattached_p.h \ - $$PWD/qqmlabstractexpression_p.h \ $$PWD/qqmljavascriptexpression_p.h \ $$PWD/qqmlabstractbinding_p.h \ $$PWD/qqmlvaluetypeproxybinding_p.h \ diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp index 40c8f451b4..4e0763e95a 100644 --- a/src/qml/qml/qqmlabstractbinding.cpp +++ b/src/qml/qml/qqmlabstractbinding.cpp @@ -39,24 +39,19 @@ QT_BEGIN_NAMESPACE -extern QQmlAbstractBinding::VTable QQmlBinding_vtable; -extern QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable; - -QQmlAbstractBinding::VTable *QQmlAbstractBinding::vTables[] = { - &QQmlBinding_vtable, - &QQmlValueTypeProxyBinding_vtable -}; - -QQmlAbstractBinding::QQmlAbstractBinding(BindingType bt) - : m_nextBindingPtr(bt) +QQmlAbstractBinding::QQmlAbstractBinding() + : m_targetIndex(-1) { + Q_ASSERT(!isAddedToObject()); } QQmlAbstractBinding::~QQmlAbstractBinding() { - Q_ASSERT(isAddedToObject() == false); - Q_ASSERT(nextBinding() == 0); - Q_ASSERT(*m_mePtr == 0); + Q_ASSERT(!ref); + Q_ASSERT(!isAddedToObject()); + + if (m_nextBinding.data() && !m_nextBinding->ref.deref()) + delete m_nextBinding.data(); } /*! @@ -72,40 +67,45 @@ void QQmlAbstractBinding::addToObject() Q_ASSERT(!nextBinding()); Q_ASSERT(isAddedToObject() == false); - QObject *obj = object(); + QObject *obj = targetObject(); Q_ASSERT(obj); QQmlData *data = QQmlData::get(obj, true); int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(propertyIndex(), &coreIndex) != -1) { + if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { // Value type // Find the value type proxy (if there is one) QQmlValueTypeProxyBinding *proxy = 0; if (data->hasBindingBit(coreIndex)) { QQmlAbstractBinding *b = data->bindings; - while (b && b->propertyIndex() != coreIndex) + while (b && b->targetPropertyIndex() != coreIndex) b = b->nextBinding(); - Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy); + Q_ASSERT(b && b->isValueTypeProxy()); proxy = static_cast<QQmlValueTypeProxyBinding *>(b); } if (!proxy) { proxy = new QQmlValueTypeProxyBinding(obj, coreIndex); - Q_ASSERT(proxy->propertyIndex() == coreIndex); - Q_ASSERT(proxy->object() == obj); + Q_ASSERT(proxy->targetPropertyIndex() == coreIndex); + Q_ASSERT(proxy->targetObject() == obj); proxy->addToObject(); } - setNextBinding(proxy->m_bindings); + setNextBinding(proxy->m_bindings.data()); proxy->m_bindings = this; } else { setNextBinding(data->bindings); + if (data->bindings) { + data->bindings->ref.deref(); + Q_ASSERT(data->bindings->ref.refCount > 0); + } data->bindings = this; + ref.ref(); data->setBindingBit(obj, coreIndex); } @@ -118,95 +118,81 @@ Remove the binding from the object. */ void QQmlAbstractBinding::removeFromObject() { - if (isAddedToObject()) { - QObject *obj = object(); - QQmlData *data = QQmlData::get(obj, false); - Q_ASSERT(data); - - int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(propertyIndex(), &coreIndex) != -1) { - - // Find the value type binding - QQmlAbstractBinding *vtbinding = data->bindings; - while (vtbinding->propertyIndex() != coreIndex) { - vtbinding = vtbinding->nextBinding(); - Q_ASSERT(vtbinding); - } - Q_ASSERT(vtbinding->bindingType() == QQmlAbstractBinding::ValueTypeProxy); - - QQmlValueTypeProxyBinding *vtproxybinding = - static_cast<QQmlValueTypeProxyBinding *>(vtbinding); - - QQmlAbstractBinding *binding = vtproxybinding->m_bindings; - if (binding == this) { - vtproxybinding->m_bindings = nextBinding(); - } else { - while (binding->nextBinding() != this) { - binding = binding->nextBinding(); - Q_ASSERT(binding); - } - binding->setNextBinding(nextBinding()); - } - - // Value type - we don't remove the proxy from the object. It will sit their happily - // doing nothing until it is removed by a write, a binding change or it is reused - // to hold more sub-bindings. + if (!isAddedToObject()) + return; - } else { + setAddedToObject(false); - if (data->bindings == this) { - data->bindings = nextBinding(); - } else { - QQmlAbstractBinding *binding = data->bindings; - while (binding->nextBinding() != this) { - binding = binding->nextBinding(); - Q_ASSERT(binding); - } - binding->setNextBinding(nextBinding()); - } - - data->clearBindingBit(coreIndex); - } + QObject *obj = targetObject(); + QQmlData *data = QQmlData::get(obj, false); + Q_ASSERT(data); - setNextBinding(0); - setAddedToObject(false); - } -} + QQmlAbstractBinding::Ptr next; + next = nextBinding(); + setNextBinding(0); -void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) -{ - qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); -} + int coreIndex; + if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { + // Find the value type binding + QQmlAbstractBinding *vtbinding = data->bindings; + while (vtbinding->targetPropertyIndex() != coreIndex) { + vtbinding = vtbinding->nextBinding(); + Q_ASSERT(vtbinding); + } + Q_ASSERT(vtbinding->isValueTypeProxy()); -static void bindingDummyDeleter(QQmlAbstractBinding *) -{ -} + QQmlValueTypeProxyBinding *vtproxybinding = + static_cast<QQmlValueTypeProxyBinding *>(vtbinding); -QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer() -{ - if (m_mePtr.value().isNull()) - m_mePtr.value() = QSharedPointer<QQmlAbstractBinding>(this, bindingDummyDeleter); + QQmlAbstractBinding *binding = vtproxybinding->m_bindings.data(); + if (binding == this) { + vtproxybinding->m_bindings = next; + } else { + while (binding->nextBinding() != this) { + binding = binding->nextBinding(); + Q_ASSERT(binding); + } + binding->setNextBinding(next.data()); + } - return m_mePtr.value().toWeakRef(); -} + // Value type - we don't remove the proxy from the object. It will sit their happily + // doing nothing until it is removed by a write, a binding change or it is reused + // to hold more sub-bindings. + return; + } -void QQmlAbstractBinding::clear() -{ - if (!m_mePtr.isNull()) { - **m_mePtr = 0; - m_mePtr = 0; + if (data->bindings == this) { + if (next.data()) + next->ref.ref(); + data->bindings = next.data(); + if (!ref.deref()) + delete this; + } else { + QQmlAbstractBinding *binding = data->bindings; + while (binding->nextBinding() != this) { + binding = binding->nextBinding(); + Q_ASSERT(binding); + } + binding->setNextBinding(next.data()); } + + data->clearBindingBit(coreIndex); } -void QQmlAbstractBinding::default_retargetBinding(QQmlAbstractBinding *, QObject *, int) +void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) { - qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding."); + qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); } -QString QQmlAbstractBinding::default_expression(const QQmlAbstractBinding *) +QString QQmlAbstractBinding::expression() const { return QLatin1String("<Unknown>"); } +bool QQmlAbstractBinding::isValueTypeProxy() const +{ + return false; +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index b5d8181ca5..dd14301aa9 100644 --- a/src/qml/qml/qqmlabstractbinding_p.h +++ b/src/qml/qml/qqmlabstractbinding_p.h @@ -46,6 +46,7 @@ // #include <QtCore/qsharedpointer.h> +#include <QtCore/qshareddata.h> #include <private/qtqmlglobal_p.h> #include <private/qqmlproperty_p.h> #include <private/qpointervaluepair_p.h> @@ -56,162 +57,83 @@ class QQmlObjectCreator; class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding { +protected: + QQmlAbstractBinding(); public: - enum DestroyMode { - - // The binding should disconnect itself upon destroy - DisconnectBinding, - - // The binding doesn't need to disconnect itself, but it can if it wants to. - // - // This is used in QQmlData::destroyed() - at the point at which the bindings are - // destroyed, the notifiers are already disconnected, so no need to disconnect each - // binding again. - // - // Bindings can use this flag to speed up destruction, especially for v4 bindings - // disconnecting a single binding might be slow. - KeepBindingConnected - }; - - struct VTable { - void (*destroy)(QQmlAbstractBinding *, DestroyMode destroyMode); - QString (*expression)(const QQmlAbstractBinding *); - int (*propertyIndex)(const QQmlAbstractBinding *); - QObject *(*object)(const QQmlAbstractBinding *); - void (*setEnabled)(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - void (*update)(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - void (*retargetBinding)(QQmlAbstractBinding *, QObject *, int); - }; - - typedef QWeakPointer<QQmlAbstractBinding> Pointer; + virtual ~QQmlAbstractBinding(); - enum BindingType { Binding = 0, ValueTypeProxy = 1 }; - inline BindingType bindingType() const; + typedef QExplicitlySharedDataPointer<QQmlAbstractBinding> Ptr; - // Destroy the binding. Use this instead of calling delete. - // Bindings are free to implement their own memory management, so the delete operator is - // not necessarily safe. The default implementation clears the binding, removes it from - // the object and calls delete. - void destroy(DestroyMode destroyMode = DisconnectBinding) - { vtable()->destroy(this, destroyMode); } + virtual QString expression() const; - QString expression() const { return vtable()->expression(this); } + virtual bool isValueTypeProxy() const; // Should return the encoded property index for the binding. Should return this value // even if the binding is not enabled or added to an object. // Encoding is: coreIndex | (valueTypeIndex << 16) - int propertyIndex() const { return vtable()->propertyIndex(this); } + int targetPropertyIndex() const { return m_targetIndex; } // Should return the object for the binding. Should return this object even if the // binding is not enabled or added to the object. - QObject *object() const { return vtable()->object(this); } - - void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); } - void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f) { vtable()->setEnabled(this, e, f); } + QObject *targetObject() const { return m_target.data(); } - void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } - void update(QQmlPropertyPrivate::WriteFlags f) { vtable()->update(this, f); } + virtual void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f = QQmlPropertyPrivate::DontRemoveBinding) = 0; void addToObject(); void removeFromObject(); - static inline Pointer getPointer(QQmlAbstractBinding *p); static void printBindingLoopError(QQmlProperty &prop); - // Default implementation for some VTable functions - template<typename T> - static void default_destroy(QQmlAbstractBinding *, DestroyMode); - static QString default_expression(const QQmlAbstractBinding *); - static void default_retargetBinding(QQmlAbstractBinding *, QObject *, int); - -protected: - QQmlAbstractBinding(BindingType); - ~QQmlAbstractBinding(); - void clear(); + inline QQmlAbstractBinding *nextBinding() const; - // Called by QQmlPropertyPrivate to "move" a binding to a different property. - // This is only used for alias properties. The default implementation qFatal()'s - // to ensure that the method is never called for binding types that don't support it. - void retargetBinding(QObject *o, int i) { vtable()->retargetBinding(this, o, i); } -private: - Pointer weakPointer(); + struct RefCount { + RefCount() : refCount(0) {} + int refCount; + void ref() { ++refCount; } + int deref() { return --refCount; } + operator int() const { return refCount; } + }; + RefCount ref; +protected: friend class QQmlData; - friend class QQmlComponentPrivate; friend class QQmlValueTypeProxyBinding; - friend class QQmlPropertyPrivate; - friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>; - friend class QV4Bindings; friend class QQmlObjectCreator; - typedef QSharedPointer<QQmlAbstractBinding> SharedPointer; - // To save memory, we also store the rarely used weakPointer() instance in here - // We also use the flag bits: - // m_mePtr.flag1: added to object - QPointerValuePair<QQmlAbstractBinding*, SharedPointer> m_mePtr; - inline void setAddedToObject(bool v); inline bool isAddedToObject() const; - inline QQmlAbstractBinding *nextBinding() const; inline void setNextBinding(QQmlAbstractBinding *); + int m_targetIndex; + QFlagPointer<QObject> m_target; // Pointer to the next binding in the linked list of bindings. - // Being a pointer, the address is always aligned to at least 4 bytes, which means the last two - // bits of the pointer are free to be used for something else. They are used to store the binding - // type. The binding type serves as an index into the static vTables array, which is used instead - // of a compiler-generated vTable. Instead of virtual functions, pointers to static functions in - // the vTables array are used for dispatching. - // This saves a compiler-generated pointer to a compiler-generated vTable, and thus reduces - // the binding object size by sizeof(void*). - qintptr m_nextBindingPtr; - - static VTable *vTables[]; - inline const VTable *vtable() const { return vTables[bindingType()]; } + QFlagPointer<QQmlAbstractBinding> m_nextBinding; }; -QQmlAbstractBinding::Pointer -QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p) -{ - return p ? p->weakPointer() : Pointer(); -} - void QQmlAbstractBinding::setAddedToObject(bool v) { - m_mePtr.setFlagValue(v); + m_nextBinding.setFlagValue(v); } bool QQmlAbstractBinding::isAddedToObject() const { - return m_mePtr.flag(); + return m_nextBinding.flag(); } QQmlAbstractBinding *QQmlAbstractBinding::nextBinding() const { - return (QQmlAbstractBinding *)(m_nextBindingPtr & ~0x3); + return m_nextBinding.data(); } void QQmlAbstractBinding::setNextBinding(QQmlAbstractBinding *b) { - m_nextBindingPtr = qintptr(b) | (m_nextBindingPtr & 0x3); -} - -QQmlAbstractBinding::BindingType QQmlAbstractBinding::bindingType() const -{ - return (BindingType)(m_nextBindingPtr & 0x3); -} - -template<typename T> -void QQmlAbstractBinding::default_destroy(QQmlAbstractBinding *This, DestroyMode mode) -{ - // Assume the binding disconnects itself in the destructor, which for example QQmlBinding - // does in the destructor of its base class, QQmlJavaScriptExpression - Q_UNUSED(mode); - - This->removeFromObject(); - This->clear(); - delete static_cast<T *>(This); + if (b) + b->ref.ref(); + if (m_nextBinding.data() && !m_nextBinding->ref.deref()) + delete m_nextBinding.data(); + m_nextBinding = b; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h deleted file mode 100644 index 82ba010434..0000000000 --- a/src/qml/qml/qqmlabstractexpression_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLABSTRACTEXPRESSION_P_H -#define QQMLABSTRACTEXPRESSION_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 <private/qqmlcontext_p.h> -#include <private/qfieldlist_p.h> -#include <private/qflagpointer_p.h> - -QT_BEGIN_NAMESPACE - -class Q_QML_PRIVATE_EXPORT QQmlAbstractExpression -{ -public: - QQmlAbstractExpression(); - virtual ~QQmlAbstractExpression(); - - bool isValid() const; - - QQmlContextData *context() const; - void setContext(QQmlContextData *); - - virtual void refresh(); - - class DeleteWatcher { - public: - inline DeleteWatcher(QQmlAbstractExpression *); - inline ~DeleteWatcher(); - inline bool wasDeleted() const; - private: - friend class QQmlAbstractExpression; - QQmlContextData *_c; - QQmlAbstractExpression **_w; - QQmlAbstractExpression *_s; - }; - -private: - friend class QQmlContext; - friend class QQmlContextData; - friend class QQmlContextPrivate; - - QBiPointer<QQmlContextData, DeleteWatcher> m_context; - QQmlAbstractExpression **m_prevExpression; - QQmlAbstractExpression *m_nextExpression; -}; - -QQmlAbstractExpression::DeleteWatcher::DeleteWatcher(QQmlAbstractExpression *e) -: _c(0), _w(0), _s(e) -{ - if (e->m_context.isT1()) { - _w = &_s; - _c = e->m_context.asT1(); - e->m_context = this; - } else { - // Another watcher is already registered - _w = &e->m_context.asT2()->_s; - } -} - -QQmlAbstractExpression::DeleteWatcher::~DeleteWatcher() -{ - Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_context.isT2())); - if (*_w && _s->m_context.asT2() == this) - _s->m_context = _c; -} - -bool QQmlAbstractExpression::DeleteWatcher::wasDeleted() const -{ - return *_w == 0; -} - -QT_END_NAMESPACE - -#endif // QQMLABSTRACTEXPRESSION_P_H diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index f223d099e4..b0ccf9ac59 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -43,43 +43,27 @@ #include <private/qqmlscriptstring_p.h> #include <private/qqmlcontextwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> +#include <private/qqmlvmemetaobject_p.h> #include <QVariant> #include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE -// Used in qqmlabstractbinding.cpp -QQmlAbstractBinding::VTable QQmlBinding_vtable = { - QQmlAbstractBinding::default_destroy<QQmlBinding>, - QQmlBinding::expression, - QQmlBinding::propertyIndex, - QQmlBinding::object, - QQmlBinding::setEnabled, - QQmlBinding::update, - QQmlBinding::retargetBinding -}; - -QQmlBinding::Identifier QQmlBinding::Invalid = -1; - -static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = { - QQmlBinding::expressionIdentifier, - QQmlBinding::expressionChanged -}; - QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt)); + QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(context(), obj, str, QString(), 0)); + createQmlBinding(context(), obj, str, QString(), 0); } QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { if (ctxt && !ctxt->isValid()) return; @@ -100,51 +84,52 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte } setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); + QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); setScopeObject(obj ? obj : scriptPrivate->scope); QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); if (runtimeFunction) { - v4function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); + m_function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); } else { QString code = scriptPrivate->script; - v4function.set(v4, qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber)); + createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); } } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(ctxt, obj, str, QString(), 0)); + createQmlBinding(ctxt, obj, str, QString(), 0); } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt, const QString &url, quint16 lineNumber, quint16 columnNumber) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { Q_UNUSED(columnNumber); setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(ctxt, obj, str, url, lineNumber)); + createQmlBinding(ctxt, obj, str, url, lineNumber); } QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - v4function.set(functionPtr.asObject()->engine(), functionPtr); + m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); } QQmlBinding::~QQmlBinding() @@ -162,90 +147,238 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) return; // Check that the target has not been deleted - if (QQmlData::wasDeleted(object())) + if (QQmlData::wasDeleted(targetObject())) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedFunctionObject f(scope, v4function.value()); + QV4::ScopedFunctionObject f(scope, m_function.value()); Q_ASSERT(f); - if (!updatingFlag()) { - QQmlBindingProfiler prof(ep->profiler, f); - setUpdatingFlag(true); + if (updatingFlag()) { + QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0); + QQmlAbstractBinding::printBindingLoopError(p); + return; + } + + QQmlBindingProfiler prof(ep->profiler, f); + setUpdatingFlag(true); - QQmlAbstractExpression::DeleteWatcher watcher(this); + QQmlJavaScriptExpression::DeleteWatcher watcher(this); - if (m_core.propType == qMetaTypeId<QQmlBinding *>()) { + QQmlPropertyData pd = getPropertyData(); - int idx = m_core.coreIndex; - Q_ASSERT(idx != -1); + if (pd.propType == qMetaTypeId<QQmlBinding *>()) { - QQmlBinding *t = this; - int status = -1; - void *a[] = { &t, 0, &status, &flags }; - QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a); + int idx = pd.coreIndex; + Q_ASSERT(idx != -1); - } else { - ep->referenceScarceResources(); + QQmlBinding *t = this; + int status = -1; + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a); - bool isUndefined = false; + } else { + ep->referenceScarceResources(); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined)); + bool isUndefined = false; - bool needsErrorLocationData = false; - if (!watcher.wasDeleted() && !hasError()) - needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(), - this, result, isUndefined, flags); + QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); - if (!watcher.wasDeleted()) { + bool error = false; + if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) + error = !write(pd, result, isUndefined, flags); - if (needsErrorLocationData) - delayedError()->setErrorLocation(f->sourceLocation()); + if (!watcher.wasDeleted()) { - if (hasError()) { - if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine)); - } else { - clearError(); - } + if (error) { + delayedError()->setErrorLocation(f->sourceLocation()); + delayedError()->setErrorObject(m_target.data()); + } + if (hasError()) { + if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine)); + } else { + clearError(); } - ep->dereferenceScarceResources(); } - if (!watcher.wasDeleted()) - setUpdatingFlag(false); - } else { - QQmlProperty p = property(); - QQmlAbstractBinding::printBindingLoopError(p); + ep->dereferenceScarceResources(); } + + if (!watcher.wasDeleted()) + setUpdatingFlag(false); +} + +// Returns true if successful, false if an error description was set on expression +bool QQmlBinding::write(const QQmlPropertyData &core, + const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags) +{ + Q_ASSERT(m_target.data()); + Q_ASSERT(core.coreIndex != -1); + + QQmlEngine *engine = context()->engine; + QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); + +#define QUICK_STORE(cpptype, conversion) \ + { \ + cpptype o = (conversion); \ + int status = -1; \ + void *argv[] = { &o, 0, &status, &flags }; \ + QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \ + return true; \ + } \ + + + if (!isUndefined && !core.isValueTypeVirtual()) { + switch (core.propType) { + case QMetaType::Int: + if (result.isInteger()) + QUICK_STORE(int, result.integerValue()) + else if (result.isNumber()) + QUICK_STORE(int, result.doubleValue()) + break; + case QMetaType::Double: + if (result.isNumber()) + QUICK_STORE(double, result.asDouble()) + break; + case QMetaType::Float: + if (result.isNumber()) + QUICK_STORE(float, result.asDouble()) + break; + case QMetaType::QString: + if (result.isString()) + QUICK_STORE(QString, result.toQStringNoThrow()) + break; + default: + break; + } + } +#undef QUICK_STORE + + int type = core.isValueTypeVirtual() ? core.valueTypePropType : core.propType; + + QQmlJavaScriptExpression::DeleteWatcher watcher(this); + + QVariant value; + bool isVarProperty = core.isVarProperty(); + + if (isUndefined) { + } else if (core.isQList()) { + value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); + } else if (result.isNull() && core.isQObject()) { + value = QVariant::fromValue((QObject *)0); + } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { + value = QQmlPropertyPrivate::resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context()); + } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { + value = QV8Engine::getV4(v8engine)->toVariant(result, type); + } + + if (hasError()) { + return false; + } else if (isVarProperty) { + const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); + if (f && f->isBinding()) { + // we explicitly disallow this case to avoid confusion. Users can still store one + // in an array in a var property if they need to, but the common case is user error. + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data()); + Q_ASSERT(vmemo); + vmemo->setVMEProperty(core.coreIndex, result); + } else if (isUndefined && core.isResettable()) { + void *args[] = { 0 }; + QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex, args); + } else if (isUndefined && type == qMetaTypeId<QVariant>()) { + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant(), context(), flags); + } else if (type == qMetaTypeId<QJSValue>()) { + const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); + if (f && f->isBinding()) { + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant::fromValue( + QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), + context(), flags); + } else if (isUndefined) { + QString errorStr = QLatin1String("Unable to assign [undefined] to "); + if (!QMetaType::typeName(type)) + errorStr += QLatin1String("[unknown property type]"); + else + errorStr += QLatin1String(QMetaType::typeName(type)); + delayedError()->setErrorDescription(errorStr); + return false; + } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) { + if (f->isBinding()) + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + else + delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); + return false; + } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, value, context(), flags)) { + + if (watcher.wasDeleted()) + return true; + + const char *valueType = 0; + const char *propertyType = 0; + + if (value.userType() == QMetaType::QObjectStar) { + if (QObject *o = *(QObject **)value.constData()) { + valueType = o->metaObject()->className(); + + QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); + if (!propertyMetaObject.isNull()) + propertyType = propertyMetaObject.className(); + } + } else if (value.userType() != QVariant::Invalid) { + if (value.userType() == QMetaType::VoidStar) + valueType = "null"; + else + valueType = QMetaType::typeName(value.userType()); + } + + if (!valueType) + valueType = "undefined"; + if (!propertyType) + propertyType = QMetaType::typeName(type); + if (!propertyType) + propertyType = "[unknown property type]"; + + delayedError()->setErrorDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(propertyType)); + return false; + } + + return true; } QVariant QQmlBinding::evaluate() { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); bool isUndefined = false; - QV4::ScopedValue f(scope, v4function.value()); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined)); + QV4::Scope scope(ep->v4engine()); + QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); ep->dereferenceScarceResources(); return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >()); } -QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlBinding::expressionIdentifier() { - QQmlBinding *This = static_cast<QQmlBinding *>(e); - - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedValue f(scope, This->v4function.value()); - QV4::Function *function = f->asFunctionObject()->function(); + QV4::ScopedValue f(scope, m_function.value()); + QV4::Function *function = f->as<QV4::FunctionObject>()->function(); QString url = function->sourceFile(); quint16 lineNumber = function->compiledFunction->location.line; @@ -254,10 +387,9 @@ QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber); } -void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e) +void QQmlBinding::expressionChanged() { - QQmlBinding *This = static_cast<QQmlBinding *>(e); - This->update(); + update(); } void QQmlBinding::refresh() @@ -265,36 +397,6 @@ void QQmlBinding::refresh() update(); } -QString QQmlBinding::expression(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->expression(); -} - -int QQmlBinding::propertyIndex(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->propertyIndex(); -} - -QObject *QQmlBinding::object(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->object(); -} - -void QQmlBinding::setEnabled(QQmlAbstractBinding *This, bool e, QQmlPropertyPrivate::WriteFlags f) -{ - static_cast<QQmlBinding *>(This)->setEnabled(e, f); -} - -void QQmlBinding::update(QQmlAbstractBinding *This , QQmlPropertyPrivate::WriteFlags f) -{ - static_cast<QQmlBinding *>(This)->update(f); -} - -void QQmlBinding::retargetBinding(QQmlAbstractBinding *This, QObject *o, int i) -{ - static_cast<QQmlBinding *>(This)->retargetBinding(o, i); -} - void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) { setEnabledFlag(e); @@ -307,44 +409,97 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) QString QQmlBinding::expression() const { QV4::Scope scope(QQmlEnginePrivate::get(context()->engine)->v4engine()); - QV4::ScopedValue v(scope, v4function.value()); + QV4::ScopedValue v(scope, m_function.value()); return v->toQStringNoThrow(); } -QObject *QQmlBinding::object() const +void QQmlBinding::setTarget(const QQmlProperty &prop) { - if (m_coreObject.hasValue()) return m_coreObject.constValue()->target; - else return *m_coreObject; + setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core); } -int QQmlBinding::propertyIndex() const +void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core) { - if (m_coreObject.hasValue()) return m_coreObject.constValue()->targetProperty; - else return m_core.encodedIndex(); -} + m_target = object; -void QQmlBinding::retargetBinding(QObject *t, int i) -{ - m_coreObject.value().target = t; - m_coreObject.value().targetProperty = i; -} + if (!object) { + m_targetIndex = -1; + return; + } -void QQmlBinding::setTarget(const QQmlProperty &prop) -{ - setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core, - QQmlPropertyPrivate::get(prop)->context); -} + QQmlPropertyData pd = core; -void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, QQmlContextData *ctxt) -{ - m_coreObject = object; - m_core = core; - m_ctxt = ctxt; + if (!object) { + m_targetIndex = -1; + return; + } + + while (pd.isAlias()) { + int coreIndex = pd.coreIndex; + int valueTypeIndex = pd.getValueTypeCoreIndex(); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + + int aValueTypeIndex; + if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) { + m_target = 0; + m_targetIndex = -1; + return; + } + if (valueTypeIndex == -1) + valueTypeIndex = aValueTypeIndex; + + QQmlData *data = QQmlData::get(object, false); + if (!data || !data->propertyCache) { + m_target = 0; + m_targetIndex = -1; + return; + } + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + m_target = object; + pd = *propertyData; + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(pd.propType); + Q_ASSERT(valueTypeMetaObject); + QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); + pd.setFlags(pd.getFlags() | QQmlPropertyData::IsValueTypeVirtual); + pd.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); + pd.valueTypePropType = vtProp.userType(); + pd.valueTypeCoreIndex = valueTypeIndex; + } + } + m_targetIndex = pd.encodedIndex(); + + QQmlData *data = QQmlData::get(*m_target, true); + if (!data->propertyCache) { + data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject()); + data->propertyCache->addref(); + } } -QQmlProperty QQmlBinding::property() const +QQmlPropertyData QQmlBinding::getPropertyData() const { - return QQmlPropertyPrivate::restore(object(), m_core, *m_ctxt); + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + + QQmlData *data = QQmlData::get(*m_target, false); + Q_ASSERT(data && data->propertyCache); + + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + QQmlPropertyData d = *propertyData; + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d.propType); + Q_ASSERT(valueTypeMetaObject); + QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); + d.setFlags(d.getFlags() | QQmlPropertyData::IsValueTypeVirtual); + d.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); + d.valueTypePropType = vtProp.userType(); + d.valueTypeCoreIndex = valueTypeIndex; + } + return d; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 1e440b2e86..a435847819 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -57,16 +57,15 @@ #include <private/qpointervaluepair_p.h> #include <private/qqmlabstractbinding_p.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE class QQmlContext; class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, - public QQmlAbstractExpression, public QQmlAbstractBinding { + friend class QQmlAbstractBinding; public: QQmlBinding(const QString &, QObject *, QQmlContext *); QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *); @@ -74,84 +73,62 @@ public: QQmlBinding(const QString &, QObject *, QQmlContextData *, const QString &url, quint16 lineNumber, quint16 columnNumber); QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *); + ~QQmlBinding(); void setTarget(const QQmlProperty &); - void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *); - QQmlProperty property() const; + void setTarget(QObject *, const QQmlPropertyData &); void setNotifyOnValueChanged(bool); - // Inherited from QQmlAbstractExpression + // Inherited from QQmlJavaScriptExpression virtual void refresh(); - // "Inherited" from QQmlAbstractBinding - static QString expression(const QQmlAbstractBinding *); - static int propertyIndex(const QQmlAbstractBinding *); - static QObject *object(const QQmlAbstractBinding *); - static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - static void retargetBinding(QQmlAbstractBinding *, QObject *, int); - - void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags); - void update(QQmlPropertyPrivate::WriteFlags flags); - void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } - - QString expression() const; - QObject *object() const; - int propertyIndex() const; - void retargetBinding(QObject *, int); + // Inherited from QQmlAbstractBinding + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); + virtual QString expression() const; + void update(QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); typedef int Identifier; - static Identifier Invalid; + enum { + Invalid = -1 + }; QVariant evaluate(); - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); - -protected: - friend class QQmlAbstractBinding; - ~QQmlBinding(); + virtual QString expressionIdentifier(); + virtual void expressionChanged(); private: - QV4::PersistentValue v4function; - inline bool updatingFlag() const; inline void setUpdatingFlag(bool); inline bool enabledFlag() const; inline void setEnabledFlag(bool); + QQmlPropertyData getPropertyData() const; - struct Retarget { - QObject *target; - int targetProperty; - }; + bool write(const QQmlPropertyData &core, + const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags); - QPointerValuePair<QObject, Retarget> m_coreObject; - QQmlPropertyData m_core; - // We store some flag bits in the following flag pointers. - // m_ctxt:flag1 - updatingFlag - // m_ctxt:flag2 - enabledFlag - QFlagPointer<QQmlContextData> m_ctxt; }; bool QQmlBinding::updatingFlag() const { - return m_ctxt.flag(); + return m_target.flag(); } void QQmlBinding::setUpdatingFlag(bool v) { - m_ctxt.setFlagValue(v); + m_target.setFlagValue(v); } bool QQmlBinding::enabledFlag() const { - return m_ctxt.flag2(); + return m_target.flag2(); } void QQmlBinding::setEnabledFlag(bool v) { - m_ctxt.setFlag2Value(v); + m_target.setFlag2Value(v); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 766e657c59..8b6f8afdce 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -47,7 +47,7 @@ #include <private/qqmlcompiler_p.h> #include "qqmlinfo.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> @@ -55,59 +55,68 @@ QT_BEGIN_NAMESPACE -static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = { - QQmlBoundSignalExpression::expressionIdentifier, - QQmlBoundSignalExpression::expressionChanged -}; - -QQmlBoundSignalExpression::ExtraData::ExtraData(const QString &handlerName, const QString ¶meterString, - const QString &expression, const QString &fileName, - quint16 line, quint16 column) - : m_handlerName(handlerName), - m_parameterString(parameterString), - m_expression(expression), - m_sourceLocation(fileName, line, column) -{ -} - QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QString &expression, const QString &fileName, quint16 line, quint16 column, const QString &handlerName, const QString ¶meterString) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_target(target), - m_extra(new ExtraData(handlerName, parameterString, expression, fileName, line, column)) + m_target(target) { - setExpressionFunctionValid(false); - setInvalidParameterName(false); - init(ctxt, scope); + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); + QV4::ExecutionEngine *v4 = ep->v4engine(); + + QString function; + + // Add some leading whitespace to account for the binding's column offset. + // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. + function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2); + function += QStringLiteral("(function "); + function += handlerName; + function += QLatin1Char('('); + + if (parameterString.isEmpty()) { + QString error; + //TODO: look at using the property cache here (as in the compiler) + // for further optimization + QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); + function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error); + + if (!error.isEmpty()) { + qmlInfo(scopeObject()) << error; + return; + } + } else + function += parameterString; + + function += QStringLiteral(") { "); + function += expression; + function += QStringLiteral(" })"); + + m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line)); + + if (m_function.isNullOrUndefined()) + return; // could not evaluate function. Not valid. + } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::Value &function) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_function(function.asObject()->engine(), function), - m_target(target), - m_extra(0) + m_target(target) { - setExpressionFunctionValid(true); - setInvalidParameterName(false); - + m_function.set(function.as<QV4::Object>()->engine(), function); init(ctxt, scope); } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_target(target), - m_extra(0) + m_target(target) { - setExpressionFunctionValid(true); - setInvalidParameterName(false); - // It's important to call init first, because m_index gets remapped in case of cloned signals. init(ctxt, scope); @@ -117,9 +126,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error)); if (!error.isEmpty()) { qmlInfo(scopeObject()) << error; - setInvalidParameterName(true); - } else - setInvalidParameterName(false); + m_function.clear(); + } } void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) @@ -134,34 +142,30 @@ void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) QQmlBoundSignalExpression::~QQmlBoundSignalExpression() { - delete m_extra.data(); } -QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlBoundSignalExpression::expressionIdentifier() { - QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e); - QQmlSourceLocation loc = This->sourceLocation(); + QQmlSourceLocation loc = sourceLocation(); return loc.sourceFile + QLatin1Char(':') + QString::number(loc.line); } -void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *) +void QQmlBoundSignalExpression::expressionChanged() { // bound signals do not notify on change. } QQmlSourceLocation QQmlBoundSignalExpression::sourceLocation() const { - if (expressionFunctionValid()) { - QV4::Function *f = function(); - Q_ASSERT(f); + QV4::Function *f = function(); + if (f) { QQmlSourceLocation loc; loc.sourceFile = f->sourceFile(); loc.line = f->compiledFunction->location.line; loc.column = f->compiledFunction->location.column; return loc; } - Q_ASSERT(!m_extra.isNull()); - return m_extra->m_sourceLocation; + return QQmlSourceLocation(); } QString QQmlBoundSignalExpression::expression() const @@ -171,10 +175,8 @@ QString QQmlBoundSignalExpression::expression() const QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); QV4::ScopedValue v(scope, m_function.value()); return v->toQStringNoThrow(); - } else { - Q_ASSERT(!m_extra.isNull()); - return m_extra->m_expression; } + return QString(); } QV4::Function *QQmlBoundSignalExpression::function() const @@ -194,108 +196,79 @@ void QQmlBoundSignalExpression::evaluate(void **a) { Q_ASSERT (context() && engine()); - if (invalidParameterName()) + if (!expressionFunctionValid()) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. - { - if (!expressionFunctionValid()) { - Q_ASSERT(!m_extra.isNull()); - QString expression; - - // Add some leading whitespace to account for the binding's column offset. - // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. - expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2); - expression += QStringLiteral("(function "); - expression += m_extra->m_handlerName; - expression += QLatin1Char('('); - - if (m_extra->m_parameterString.isEmpty()) { - QString error; - //TODO: look at using the property cache here (as in the compiler) - // for further optimization - QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); - expression += QQmlPropertyCache::signalParameterStringForJS(scope.engine, signal.parameterNames(), &error); - - if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; - setInvalidParameterName(true); - ep->dereferenceScarceResources(); - return; - } - } else - expression += m_extra->m_parameterString; - - expression += QStringLiteral(") { "); - expression += m_extra->m_expression; - expression += QStringLiteral(" })"); - - m_extra->m_expression.clear(); - m_extra->m_handlerName.clear(); - m_extra->m_parameterString.clear(); - - m_function.set(scope.engine, evalFunction(context(), scopeObject(), expression, - m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope)); - - if (m_function.isNullOrUndefined()) { - ep->dereferenceScarceResources(); - return; // could not evaluate function. Not valid. - } - - setExpressionFunctionValid(true); - } - QVarLengthArray<int, 9> dummy; - //TODO: lookup via signal index rather than method index as an optimization - int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); - int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); - int argCount = argsTypes ? *argsTypes : 0; - - QV4::ScopedValue f(scope, m_function.value()); - QV4::ScopedCallData callData(scope, argCount); - for (int ii = 0; ii < argCount; ++ii) { - int type = argsTypes[ii + 1]; - //### ideally we would use metaTypeToJS, however it currently gives different results - // for several cases (such as QVariant type and QObject-derived types) - //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); - if (type == QMetaType::QVariant) { - callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); - } else if (type == QMetaType::Int) { - //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise - callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); - } else if (type == qMetaTypeId<QQmlV4Handle>()) { - callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); - } else if (ep->isQObject(type)) { - if (!*reinterpret_cast<void* const *>(a[ii + 1])) - callData->args[ii] = QV4::Primitive::nullValue(); - else - callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); - } else { - callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1])); - } + QVarLengthArray<int, 9> dummy; + //TODO: lookup via signal index rather than method index as an optimization + int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); + int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); + int argCount = argsTypes ? *argsTypes : 0; + + QV4::ScopedCallData callData(scope, argCount); + for (int ii = 0; ii < argCount; ++ii) { + int type = argsTypes[ii + 1]; + //### ideally we would use metaTypeToJS, however it currently gives different results + // for several cases (such as QVariant type and QObject-derived types) + //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); + if (type == QMetaType::QVariant) { + callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); + } else if (type == QMetaType::Int) { + //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise + callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); + } else if (type == qMetaTypeId<QQmlV4Handle>()) { + callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); + } else if (ep->isQObject(type)) { + if (!*reinterpret_cast<void* const *>(a[ii + 1])) + callData->args[ii] = QV4::Primitive::nullValue(); + else + callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); + } else { + callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1])); } - - QQmlJavaScriptExpression::evaluate(context(), f, callData, 0); } + + QQmlJavaScriptExpression::evaluate(callData, 0); + ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } //////////////////////////////////////////////////////////////////////// -QQmlAbstractBoundSignal::QQmlAbstractBoundSignal() -: m_prevSignal(0), m_nextSignal(0) + +/*! \internal + \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner, + QQmlEngine *engine) + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlBoundSignal), + m_prevSignal(0), m_nextSignal(0), + m_expression(0) { + addToObject(owner); + + /* + If this is a cloned method, connect to the 'original'. For example, + for the signal 'void aSignal(int parameter = 0)', if the method + index refers to 'aSignal()', get the index of 'aSignal(int)'. + This ensures that 'parameter' will be available from QML. + */ + signal = QQmlPropertyCache::originalClone(target, signal); + QQmlNotifierEndpoint::connect(target, signal, engine); } -QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal() +QQmlBoundSignal::~QQmlBoundSignal() { removeFromObject(); } -void QQmlAbstractBoundSignal::addToObject(QObject *obj) +void QQmlBoundSignal::addToObject(QObject *obj) { Q_ASSERT(!m_prevSignal); Q_ASSERT(obj); @@ -308,7 +281,7 @@ void QQmlAbstractBoundSignal::addToObject(QObject *obj) data->signalHandlers = this; } -void QQmlAbstractBoundSignal::removeFromObject() +void QQmlBoundSignal::removeFromObject() { if (m_prevSignal) { *m_prevSignal = m_nextSignal; @@ -318,40 +291,6 @@ void QQmlAbstractBoundSignal::removeFromObject() } } -/*! \internal - \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()). - This is different from QMetaMethod::methodIndex(). -*/ -QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner, - QQmlEngine *engine) -: m_expression(0), m_index(signal), m_isEvaluating(false) -{ - addToObject(owner); - setCallback(QQmlNotifierEndpoint::QQmlBoundSignal); - - /* - If this is a cloned method, connect to the 'original'. For example, - for the signal 'void aSignal(int parameter = 0)', if the method - index refers to 'aSignal()', get the index of 'aSignal(int)'. - This ensures that 'parameter' will be available from QML. - */ - m_index = QQmlPropertyCache::originalClone(target, m_index); - QQmlNotifierEndpoint::connect(target, m_index, engine); -} - -QQmlBoundSignal::~QQmlBoundSignal() -{ - m_expression = 0; -} - -/*! - Returns the signal index in the range returned by QObjectPrivate::signalIndex(). - This is different from QMetaMethod::methodIndex(). -*/ -int QQmlBoundSignal::index() const -{ - return m_index; -} /*! Returns the signal expression. @@ -362,45 +301,26 @@ QQmlBoundSignalExpression *QQmlBoundSignal::expression() const } /*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. + Sets the signal expression to \a e. - The QQmlBoundSignal instance adds a reference to \a e. The caller - assumes ownership of the returned QQmlBoundSignalExpression reference. + The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). */ -QQmlBoundSignalExpressionPointer QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e) +void QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e) { - QQmlBoundSignalExpressionPointer rv = m_expression; - m_expression = e; - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; -} - -/*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. - - The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). The caller - assumes ownership of the returned QQmlBoundSignalExpression reference. -*/ -QQmlBoundSignalExpressionPointer QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e) -{ - QQmlBoundSignalExpressionPointer rv = m_expression; m_expression.take(e); - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; + if (m_expression) + m_expression->setNotifyOnValueChanged(false); } void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) { QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e); + if (!s->m_expression) return; if (QQmlDebugService::isDebuggingEnabled()) - QV4DebugService::instance()->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal(s->m_expression->target()->metaObject(), s->m_index).methodSignature())); - - s->m_isEvaluating = true; + QV4DebugService::instance()->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal(s->m_expression->target()->metaObject(), s->signalIndex()).methodSignature())); QQmlEngine *engine; if (s->m_expression && (engine = s->m_expression->engine())) { @@ -410,8 +330,6 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) QQmlEnginePrivate::warning(engine, s->m_expression->error(engine)); } } - - s->m_isEvaluating = false; } //////////////////////////////////////////////////////////////////////// diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 8d677ea039..3742317484 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -47,7 +47,6 @@ #include <QtCore/qmetaobject.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> #include <private/qqmlboundsignalexpressionpointer_p.h> #include <private/qqmlnotifier_p.h> @@ -58,7 +57,7 @@ QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpression, public QQmlJavaScriptExpression, public QQmlRefCount +class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlJavaScriptExpression, public QQmlRefCount { public: QQmlBoundSignalExpression(QObject *target, int index, @@ -73,9 +72,9 @@ public: QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction); - // "inherited" from QQmlJavaScriptExpression. - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); + // inherited from QQmlJavaScriptExpression. + virtual QString expressionIdentifier(); + virtual void expressionChanged(); // evaluation of a bound signal expression doesn't return any value void evaluate(void **a); @@ -92,80 +91,35 @@ private: void init(QQmlContextData *ctxt, QObject *scope); - bool expressionFunctionValid() const { return m_extra.flag(); } - void setExpressionFunctionValid(bool v) { m_extra.setFlagValue(v); } - - bool invalidParameterName() const { return m_extra.flag2(); } - void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); } + bool expressionFunctionValid() const { return !m_function.isNullOrUndefined(); } int m_index; - QV4::PersistentValue m_function; - QObject *m_target; - - // only needed when !expressionFunctionValid() - struct ExtraData { - ExtraData(const QString &handlerName, const QString ¶meterString, - const QString &expression, const QString &fileName, - quint16 line, quint16 column); - QString m_handlerName; - QString m_parameterString; - QString m_expression; - QQmlSourceLocation m_sourceLocation; - QV4::PersistentValue m_v8qmlscope; - }; - - // We store some flag bits in the following flag pointers. - // flag - expressionFunctionValid - // flag2 - invalidParameterName - QFlagPointer<ExtraData> m_extra; }; -class Q_QML_PRIVATE_EXPORT QQmlAbstractBoundSignal +class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint { public: - QQmlAbstractBoundSignal(); - virtual ~QQmlAbstractBoundSignal(); - - virtual int index() const = 0; - virtual QQmlBoundSignalExpression *expression() const = 0; - virtual QQmlBoundSignalExpressionPointer setExpression(QQmlBoundSignalExpression *) = 0; - virtual QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *) = 0; - virtual bool isEvaluating() const = 0; + QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine); + ~QQmlBoundSignal(); void removeFromObject(); -protected: - void addToObject(QObject *owner); + + QQmlBoundSignalExpression *expression() const; + void takeExpression(QQmlBoundSignalExpression *); private: - friend class QQmlData; + friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); friend class QQmlPropertyPrivate; + friend class QQmlData; friend class QQmlEngineDebugService; - QQmlAbstractBoundSignal **m_prevSignal; - QQmlAbstractBoundSignal *m_nextSignal; -}; -class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal, - public QQmlNotifierEndpoint -{ -public: - QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine); - virtual ~QQmlBoundSignal(); - - int index() const; - - QQmlBoundSignalExpression *expression() const; - QQmlBoundSignalExpressionPointer setExpression(QQmlBoundSignalExpression *); - QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *); + void addToObject(QObject *owner); - bool isEvaluating() const { return m_isEvaluating; } - -private: - friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); + QQmlBoundSignal **m_prevSignal; + QQmlBoundSignal *m_nextSignal; QQmlBoundSignalExpressionPointer m_expression; - int m_index; - bool m_isEvaluating; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 9210610cec..d46f612e40 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -98,7 +98,6 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); \class QQmlComponent \since 5.0 \inmodule QtQml - \mainclass \brief The QQmlComponent class encapsulates a QML component definition @@ -1216,7 +1215,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); - if (!v->asObject() || v->asArrayObject()) { + if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { qmlInfo(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; @@ -1242,12 +1241,12 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (!valuemap->isUndefined()) { QV4::ScopedObject qmlglobal(scope, args->qmlGlobal()); QV4::ScopedValue f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlglobal)); - Q_ASSERT(f->asFunctionObject()); + Q_ASSERT(f->as<QV4::FunctionObject>()); QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4->globalObject(); + callData->thisObject = v4->globalObject; callData->args[0] = object; callData->args[1] = valuemap; - f->asFunctionObject()->call(callData); + f->as<QV4::FunctionObject>()->call(callData); } d->completeCreate(); @@ -1256,10 +1255,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) QQmlData::get(rv)->explicitIndestructibleSet = false; QQmlData::get(rv)->indestructible = false; - if (!rv) - args->setReturnValue(QV4::Encode::null()); - else - args->setReturnValue(object->asReturnedValue()); + args->setReturnValue(object->asReturnedValue()); } /*! @@ -1342,7 +1338,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); if (v->isNull()) { - } else if (!v->asObject() || v->asArrayObject()) { + } else if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { qmlInfo(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; @@ -1390,14 +1386,14 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Valu QV4::Scope scope(v4engine); QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4engine, toCreate)); - Q_ASSERT(object->asObject()); + Q_ASSERT(object->as<QV4::Object>()); if (!valuemap.isUndefined()) { QV4::ScopedObject qmlGlobalObj(scope, qmlGlobal); QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4engine, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobalObj)); QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4engine->globalObject(); + callData->thisObject = v4engine->globalObject; callData->args[0] = object; callData->args[1] = valuemap; f->call(callData); @@ -1492,9 +1488,9 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) QV4::ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); - QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), d()->qmlGlobal.asObject())); + QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), d()->qmlGlobal.as<Object>())); QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4->globalObject(); + callData->thisObject = v4->globalObject; callData->args[0] = QV4::QObjectWrapper::wrap(v4, o); callData->args[1] = d()->valuemap; f->call(callData); diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 8c866c585a..121c83db5c 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -63,8 +63,8 @@ class Q_QML_EXPORT QQmlComponent : public QObject Q_PROPERTY(QUrl url READ url CONSTANT) public: - Q_ENUMS(CompilationMode) enum CompilationMode { PreferSynchronous, Asynchronous }; + Q_ENUM(CompilationMode) QQmlComponent(QObject *parent = 0); QQmlComponent(QQmlEngine *, QObject *parent=0); @@ -74,8 +74,8 @@ public: QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0); virtual ~QQmlComponent(); - Q_ENUMS(Status) enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; bool isNull() const; @@ -125,7 +125,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(QQmlComponent::Status) QML_DECLARE_TYPE(QQmlComponent) QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index f08f650913..56326df979 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -57,7 +57,6 @@ QQmlContextPrivate::QQmlContextPrivate() /*! \class QQmlContext \brief The QQmlContext class defines a context within a QML engine. - \mainclass \inmodule QtQml Contexts allow data to be exposed to the QML components instantiated by the @@ -585,9 +584,9 @@ void QQmlContextData::clearContext() { emitDestruction(); - QQmlAbstractExpression *expression = expressions; + QQmlJavaScriptExpression *expression = expressions; while (expression) { - QQmlAbstractExpression *nextExpression = expression->m_nextExpression; + QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression; expression->m_prevExpression = 0; expression->m_nextExpression = 0; @@ -652,9 +651,9 @@ void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership) } } -void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression) +void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression) { - QQmlAbstractExpression::DeleteWatcher w(expression); + QQmlJavaScriptExpression::DeleteWatcher w(expression); if (expression->m_nextExpression) refreshExpressionsRecursive(expression->m_nextExpression); @@ -808,7 +807,7 @@ QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const { if (propertyNameCache.isEmpty()) { propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle())); - for (QHash<int, int>::ConstIterator it = objectIndexToId.begin(), end = objectIndexToId.end(); + for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend(); it != end; ++it) { const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key()); const QString name = typeCompilationUnit->data->stringAt(obj->idIndex); diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index c714846147..e69a2f8f69 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -72,6 +72,7 @@ public: void setContextProperty(const QString &, QObject *); void setContextProperty(const QString &, const QVariant &); + // ### Qt 6: no need for a mutable object, this should become a const QObject pointer QString nameForObject(QObject *) const; QUrl resolvedUrl(const QUrl &); diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index f5fd7d0a5c..95254d4baa 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -69,7 +69,7 @@ class QQmlExpression; class QQmlEngine; class QQmlExpression; class QQmlExpressionPrivate; -class QQmlAbstractExpression; +class QQmlJavaScriptExpression; class QQmlContextData; class QQmlContextPrivate : public QObjectPrivate @@ -171,7 +171,7 @@ public: QQmlContextData **prevChild; // Expressions that use this context - QQmlAbstractExpression *expressions; + QQmlJavaScriptExpression *expressions; // Doubly-linked list of objects that are owned by this context QQmlData *contextObjects; @@ -212,7 +212,7 @@ public: private: void refreshExpressionsRecursive(bool isGlobal); - void refreshExpressionsRecursive(QQmlAbstractExpression *); + void refreshExpressionsRecursive(QQmlJavaScriptExpression *); ~QQmlContextData() {} }; diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 5844eab54f..fd85b64ad1 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -38,13 +38,14 @@ #include <private/qqmlcontext_p.h> #include <private/qv4engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4mm_p.h> #include <private/qv4function_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmllistwrapper_p.h> +#include <private/qqmljavascriptexpression_p.h> #include <private/qjsvalue_p.h> QT_BEGIN_NAMESPACE @@ -60,7 +61,6 @@ Heap::QmlContextWrapper::QmlContextWrapper(QV4::ExecutionEngine *engine, QQmlCon , isNullWrapper(false) , context(context) , scopeObject(scopeObject) - , idObjectsWrapper(Q_NULLPTR) { } @@ -93,49 +93,30 @@ ReturnedValue QmlContextWrapper::urlScope(ExecutionEngine *v4, const QUrl &url) return w.asReturnedValue(); } -QQmlContextData *QmlContextWrapper::callingContext(ExecutionEngine *v4) -{ - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, v4->qmlContextObject()); - - return !!c ? c->getContext() : 0; -} - QQmlContextData *QmlContextWrapper::getContext(const Value &value) { if (!value.isObject()) return 0; - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); Scope scope(v4); QV4::Scoped<QmlContextWrapper> c(scope, value); return c ? c->getContext() : 0; } -void QmlContextWrapper::takeContextOwnership(const Value &qmlglobal) -{ - Q_ASSERT(qmlglobal.isObject()); - QV4::ExecutionEngine *v4 = qmlglobal.asObject()->engine(); - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, qmlglobal); - Q_ASSERT(c); - c->d()->ownsContext = true; -} - - -ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlContextWrapper>()); - QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m); + const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m); QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); // In V8 the JS global object would come _before_ the QML global object, // so simulate that here. bool hasProp; - QV4::ScopedValue result(scope, v4->globalObject()->get(name, &hasProp)); + QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; @@ -145,7 +126,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); - if (QV4::QmlContextWrapper::callingContext(v4) != resource->d()->context) + if (v4->callingQmlContext() != resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); @@ -209,7 +190,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty if (propertyIdx < context->idValueCount) { - ep->captureProperty(&context->idValues[propertyIdx].bindings); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); if (hasProperty) *hasProperty = true; return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); @@ -217,8 +199,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty QQmlContextPrivate *cp = context->asQQmlContextPrivate(); - ep->captureProperty(context->asQQmlContext(), -1, - propertyIdx + cp->notifyIndex); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (hasProperty) @@ -278,10 +260,9 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) return; QV4::Scoped<QmlContextWrapper> wrapper(scope, resource); - PropertyAttributes attrs; - Property *pd = wrapper->__getOwnProperty__(name, &attrs); - if (pd) { - wrapper->putValue(pd, attrs, value); + uint member = wrapper->internalClass()->find(name); + if (member < UINT_MAX) { + wrapper->putValue(wrapper->propertyAt(member), wrapper->internalClass()->propertyData[member], value); return; } @@ -342,14 +323,6 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) Object::put(m, name, value); } -void QmlContextWrapper::markObjects(Heap::Base *m, ExecutionEngine *engine) -{ - QmlContextWrapper::Data *This = static_cast<QmlContextWrapper::Data *>(m); - if (This->idObjectsWrapper) - This->idObjectsWrapper->mark(engine); - Object::markObjects(m, engine); -} - void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction) { // Let the caller check and avoid the function call :) @@ -358,7 +331,7 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; if (!ep) return; - QQmlEnginePrivate::PropertyCapture *capture = ep->propertyCapture; + QQmlPropertyCapture *capture = ep->propertyCapture; if (!capture) return; @@ -393,15 +366,6 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C } -ReturnedValue QmlContextWrapper::idObjectsArray() -{ - if (!d()->idObjectsWrapper) { - ExecutionEngine *v4 = engine(); - d()->idObjectsWrapper = v4->memoryManager->alloc<QQmlIdObjectsArray>(v4, this); - } - return d()->idObjectsWrapper->asReturnedValue(); -} - ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String *name) { if (!d()->context->imports) @@ -423,20 +387,11 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String return QJSValuePrivate::convertedToValue(engine(), siinfo->scriptApi(e)); } -DEFINE_OBJECT_VTABLE(QQmlIdObjectsArray); - -Heap::QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QV4::QmlContextWrapper *contextWrapper) - : Heap::Object(engine) - , contextWrapper(contextWrapper->d()) +ReturnedValue QmlContextWrapper::getIndexed(const Managed *m, uint index, bool *hasProperty) { -} - -ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty) -{ - Scope scope(static_cast<QV4::QQmlIdObjectsArray*>(m)->engine()); - Scoped<QQmlIdObjectsArray> This(scope, static_cast<QV4::QQmlIdObjectsArray*>(m)); - Scoped<QmlContextWrapper> contextWrapper(scope, This->d()->contextWrapper); - QQmlContextData *context = contextWrapper->getContext(); + const QV4::QmlContextWrapper *This = static_cast<const QV4::QmlContextWrapper *>(m); + Scope scope(This->engine()); + QQmlContextData *context = This->getContext(); if (!context) { if (hasProperty) *hasProperty = false; @@ -452,17 +407,10 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr *hasProperty = true; QQmlEnginePrivate *ep = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : 0; - if (ep) - ep->captureProperty(&context->idValues[index].bindings); + if (ep && ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[index].bindings); return QObjectWrapper::wrap(This->engine(), context->idValues[index].data()); } -void QQmlIdObjectsArray::markObjects(Heap::Base *that, ExecutionEngine *engine) -{ - QQmlIdObjectsArray::Data *This = static_cast<QQmlIdObjectsArray::Data *>(that); - This->contextWrapper->mark(engine); - Object::markObjects(that, engine); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 52d8677103..e806077326 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qqmlcontext_p.h> #include <private/qv4functionobject_p.h> @@ -65,8 +65,6 @@ struct QmlContextWrapper; namespace Heap { -struct QQmlIdObjectsArray; - struct QmlContextWrapper : Object { QmlContextWrapper(ExecutionEngine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); ~QmlContextWrapper(); @@ -76,12 +74,6 @@ struct QmlContextWrapper : Object { QQmlGuardedContextData context; QPointer<QObject> scopeObject; - QQmlIdObjectsArray *idObjectsWrapper; -}; - -struct QQmlIdObjectsArray : Object { - QQmlIdObjectsArray(QV4::ExecutionEngine *engine, QV4::QmlContextWrapper *contextWrapper); - QmlContextWrapper *contextWrapper; }; } @@ -94,8 +86,9 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static ReturnedValue qmlScope(ExecutionEngine *e, QQmlContextData *ctxt, QObject *scope); static ReturnedValue urlScope(ExecutionEngine *v4, const QUrl &); - static QQmlContextData *callingContext(ExecutionEngine *v4); - static void takeContextOwnership(const Value &qmlglobal); + void takeContextOwnership() { + d()->ownsContext = true; + } inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return d()->context; } @@ -103,24 +96,14 @@ struct Q_QML_EXPORT QmlContextWrapper : Object void setReadOnly(bool b) { d()->readOnly = b; } - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); - static void markObjects(Heap::Base *m, ExecutionEngine *engine); static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); - ReturnedValue idObjectsArray(); ReturnedValue qmlSingletonWrapper(ExecutionEngine *e, String *name); -}; - -struct QQmlIdObjectsArray : public Object -{ - V4_OBJECT2(QQmlIdObjectsArray, Object) - - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void markObjects(Heap::Base *that, ExecutionEngine *engine); - + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; } diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 04c42b638d..3d2a76693a 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -48,8 +48,9 @@ #include <private/qtqmlglobal_p.h> #include <private/qobject_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4persistent_p.h> +#include <qjsengine.h> QT_BEGIN_NAMESPACE @@ -58,7 +59,7 @@ class QQmlEngine; class QQmlGuardImpl; class QQmlCompiledData; class QQmlAbstractBinding; -class QQmlAbstractBoundSignal; +class QQmlBoundSignal; class QQmlContext; class QQmlPropertyCache; class QQmlContextData; @@ -72,15 +73,7 @@ class QQmlNotifierEndpoint; class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: - QQmlData() - : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), - hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), - hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), - bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), - propertyCache(0), guards(0), extendedData(0) { - init(); - } + QQmlData(); static inline void init() { static bool initialized = false; @@ -158,7 +151,7 @@ public: QQmlContextData *outerContext; QQmlAbstractBinding *bindings; - QQmlAbstractBoundSignal *signalHandlers; + QQmlBoundSignal *signalHandlers; // Linked list for QQmlContext::contextObjects QQmlData *nextContextObject; diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 7f6310d58e..a45152e0a0 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -304,7 +304,9 @@ QList<QQmlError> QQmlDirParser::errors(const QString &uri) const { QUrl url(uri); QList<QQmlError> errors; - for (int i = 0; i < _errors.size(); ++i) { + const int numErrors = _errors.size(); + errors.reserve(numErrors); + for (int i = 0; i < numErrors; ++i) { const QQmlJS::DiagnosticMessage &msg = _errors.at(i); QQmlError e; QString description = msg.message; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 8cf3d2064d..fdce590873 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -225,7 +225,6 @@ void QQmlEnginePrivate::activateDesignerMode() /*! \class QQmlImageProviderBase \brief The QQmlImageProviderBase class is used to register image providers in the QML engine. - \mainclass \inmodule QtQml Image providers must be registered with the QML engine. The only information the QML @@ -247,6 +246,10 @@ void QQmlEnginePrivate::activateDesignerMode() The QQuickImageProvider::requestPixmap() method will be called for all image requests. \value Texture The Image Provider provides QSGTextureProvider based images. The QQuickImageProvider::requestTexture() method will be called for all image requests. + \value ImageResponse The Image provider provides QQuickTextureFactory based images. + Should only be used in QQuickAsyncImageProvider or its subclasses. + The QQuickAsyncImageProvider::requestImageResponse() method will be called for all image requests. + Since Qt 5.6 \omitvalue Invalid */ @@ -595,8 +598,8 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) QQmlEnginePrivate::~QQmlEnginePrivate() { - typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator TypePropertyCacheIt; - typedef QHash<int, QQmlCompiledData *>::Iterator CompositeTypesIt; + typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt; + typedef QHash<int, QQmlCompiledData *>::const_iterator CompositeTypesIt; if (inProgressCreations) qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations); @@ -615,9 +618,9 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - for (TypePropertyCacheIt iter = typePropertyCache.begin(), end = typePropertyCache.end(); iter != end; ++iter) + for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter) (*iter)->release(); - for (CompositeTypesIt iter = m_compositeTypes.begin(), end = m_compositeTypes.end(); iter != end; ++iter) { + for (CompositeTypesIt iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; // since unregisterInternalCompositeType() will not be called in this @@ -654,6 +657,17 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) } } +QQmlData::QQmlData() + : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), + hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), + hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), + bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), + lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), + propertyCache(0), guards(0), extendedData(0) +{ + init(); +} + void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) { QQmlData *ddata = static_cast<QQmlData *>(d); @@ -787,7 +801,7 @@ void QQmlData::markAsDeleted(QObject *o) QQmlData::setQueuedForDeletion(o); QObjectPrivate *p = QObjectPrivate::get(o); - for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) { + for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) { QQmlData::markAsDeleted(*it); } } @@ -812,14 +826,12 @@ void QQmlData::flushPendingBindingImpl(int coreIndex) // Find the binding QQmlAbstractBinding *b = bindings; - while (b && *b->m_mePtr && b->propertyIndex() != coreIndex) + while (b && b->targetPropertyIndex() != coreIndex) b = b->nextBinding(); - if (b && b->propertyIndex() == coreIndex) { - b->clear(); + if (b && b->targetPropertyIndex() == coreIndex) b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); - } } bool QQmlEnginePrivate::baseModulesUninitialized = true; @@ -874,7 +886,6 @@ QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() \since 5.0 \inmodule QtQml \brief The QQmlEngine class provides an environment for instantiating QML components. - \mainclass Each QML component is instantiated in a QQmlContext. QQmlContext's are essential for passing data to QML @@ -1490,38 +1501,6 @@ QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning) #endif } -/*! - * \enum QQmlDebuggingEnabler::StartMode - * - * Defines the debug server's start behavior. You can interrupt QML engines starting while a debug - * client is connecting, in order to set breakpoints in or profile startup code. - * - * \value DoNotWaitForClient Run any QML engines as usual while the debug services are connecting. - * \value WaitForClient If a QML engine starts while the debug services are connecting, - * interrupt it until they are done. - */ - -/*! - * Enables debugging for QML engines created after calling this function. The debug server will - * listen on \a port at \a hostName and block the QML engine until it receives a connection if - * \a mode is \c WaitForClient. If \a mode is not specified it won't block and if \a hostName is not - * specified it will listen on all available interfaces. You can only start one debug server at a - * time. A debug server may have already been started if the -qmljsdebugger= command line argument - * was given. This method returns \c true if a new debug server was successfully started, or - * \c false otherwise. - */ -bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) -{ -#ifndef QQML_NO_DEBUG_PROTOCOL - return QQmlDebugServer::enable(port, port, mode == WaitForClient, hostName); -#else - Q_UNUSED(port); - Q_UNUSED(block); - Q_UNUSED(hostName); - return false; -#endif -} - class QQmlDataExtended { public: QQmlDataExtended(); @@ -1651,12 +1630,11 @@ void QQmlData::destroyed(QObject *object) QQmlAbstractBinding *binding = bindings; while (binding) { - QQmlAbstractBinding *next = binding->nextBinding(); binding->setAddedToObject(false); - binding->setNextBinding(0); - binding->destroy(); - binding = next; + binding = binding->nextBinding(); } + if (bindings && !bindings->ref.deref()) + delete bindings; if (compiledData) { compiledData->release(); @@ -1669,9 +1647,9 @@ void QQmlData::destroyed(QObject *object) deferredData = 0; } - QQmlAbstractBoundSignal *signalHandler = signalHandlers; + QQmlBoundSignal *signalHandler = signalHandlers; while (signalHandler) { - if (signalHandler->isEvaluating()) { + if (signalHandler->isNotifying()) { // The object is being deleted during signal handler evaluation. // This will cause a crash due to invalid memory access when the // evaluation has completed. @@ -1700,7 +1678,7 @@ void QQmlData::destroyed(QObject *object) "%s", object, qPrintable(locationString)); } - QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal; + QQmlBoundSignal *next = signalHandler->m_nextSignal; signalHandler->m_prevSignal = 0; signalHandler->m_nextSignal = 0; delete signalHandler; @@ -2113,8 +2091,7 @@ QString QQmlEngine::offlineStoragePath() const return d->offlineStoragePath; } -QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion, - QQmlError &error) +QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion) { QList<QQmlType *> types; @@ -2176,10 +2153,10 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi // Properties override: // * other elements of the same name +#if 0 bool overloadError = false; QString overloadName; -#if 0 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); !overloadError && iter != raw->stringCache.end(); ++iter) { @@ -2196,7 +2173,6 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi overloadError = true; } } -#endif if (overloadError) { if (hasCopied) raw->release(); @@ -2204,6 +2180,7 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1Char(' ') + QString::number(type->majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); return 0; } +#endif if (!hasCopied) raw->addref(); typePropertyCache.insert(qMakePair(type, minorVersion), raw); @@ -2254,8 +2231,8 @@ bool QQmlEnginePrivate::isList(int t) const int QQmlEnginePrivate::listType(int t) const { Locker locker(this); - QHash<int, int>::ConstIterator iter = m_qmlLists.find(t); - if (iter != m_qmlLists.end()) + QHash<int, int>::ConstIterator iter = m_qmlLists.constFind(t); + if (iter != m_qmlLists.cend()) return *iter; else return QQmlMetaType::listType(t); @@ -2264,8 +2241,8 @@ int QQmlEnginePrivate::listType(int t) const QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2276,8 +2253,8 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2288,8 +2265,8 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2301,8 +2278,8 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index df673c1fd5..61a884279d 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -52,7 +52,9 @@ public: Image, Pixmap, Texture, - Invalid + Invalid, + ImageResponse + // ### Qt6: reorder these, and give Invalid a fixed large value }; enum Flag { diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index f1fbad3cf8..1a317f6fbd 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -85,7 +85,6 @@ class QQmlImportDatabase; class QNetworkReply; class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; -class QQmlAbstractBinding; class QQmlTypeNameCache; class QQmlComponentAttached; class QQmlCleanup; @@ -95,6 +94,7 @@ class QQmlObjectCreator; class QDir; class QQmlIncubator; class QQmlProfiler; +class QQmlPropertyCapture; // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. // The inline method definitions are in qqmljavascriptexpression_p.h @@ -123,16 +123,7 @@ public: // is just qmlClearTypeRegistrations (which can't be called while an engine exists) static bool baseModulesUninitialized; - class PropertyCapture { - public: - inline virtual ~PropertyCapture() {} - virtual void captureProperty(QQmlNotifier *) = 0; - virtual void captureProperty(QObject *, int, int) = 0; - }; - - PropertyCapture *propertyCapture; - inline void captureProperty(QQmlNotifier *); - inline void captureProperty(QObject *, int, int); + QQmlPropertyCapture *propertyCapture; QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool; @@ -208,7 +199,7 @@ public: inline static void deleteInEngineThread(QQmlEngine *, T *); // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error); + inline QQmlPropertyCache *cache(QQmlType *, int); using QJSEnginePrivate::cache; // These methods may be called from the loader thread @@ -262,7 +253,7 @@ public: private: // Must be called locked - QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error); + QQmlPropertyCache *createCache(QQmlType *, int); // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. @@ -346,7 +337,7 @@ Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error) +QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion) { Q_ASSERT(type); @@ -355,7 +346,7 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQ Locker locker(this); QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); - if (!rv) rv = createCache(type, minorVersion, error); + if (!rv) rv = createCache(type, minorVersion); return rv; } @@ -414,18 +405,6 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) return get(qmlEngine); } -void QQmlEnginePrivate::captureProperty(QQmlNotifier *n) -{ - if (propertyCapture) - propertyCapture->captureProperty(n); -} - -void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n) -{ - if (propertyCapture) - propertyCapture->captureProperty(o, c, n); -} - void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes) { Locker locker(this); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 35e0bc8c64..332b99ee8f 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -45,13 +45,8 @@ QT_BEGIN_NAMESPACE -static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = { - QQmlExpressionPrivate::expressionIdentifier, - QQmlExpressionPrivate::expressionChanged -}; - QQmlExpressionPrivate::QQmlExpressionPrivate() -: QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable), +: QQmlJavaScriptExpression(), expressionFunctionValid(true), line(0), column(0) { @@ -65,7 +60,7 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb { expression = expr; - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); expressionFunctionValid = false; } @@ -74,9 +69,9 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFu { expressionFunctionValid = true; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); + m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); } @@ -246,18 +241,12 @@ void QQmlExpression::setExpression(const QString &expression) // Must be called with a valid handle scope QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined) { - Q_Q(QQmlExpression); - - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(q->engine())->v4engine(); - if (!expressionFunctionValid) { - function.set(v4, qmlBinding(context(), scopeObject(), expression, url, line, &qmlscope)); + createQmlBinding(context(), scopeObject(), expression, url, line); expressionFunctionValid = true; } - QV4::Scope scope(v4); - QV4::ScopedValue f(scope, function.value()); - return evaluate(context(), f, isUndefined); + return evaluate(isUndefined); } QVariant QQmlExpressionPrivate::value(bool *isUndefined) @@ -432,22 +421,15 @@ QQmlError QQmlExpression::error() const calling QQmlExpression::evaluate()) before this signal will be emitted. */ -void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e) -{ - QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e); - This->expressionChanged(); -} - void QQmlExpressionPrivate::expressionChanged() { Q_Q(QQmlExpression); emit q->valueChanged(); } -QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlExpressionPrivate::expressionIdentifier() { - QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e); - return QLatin1Char('"') + This->expression + QLatin1Char('"'); + return QLatin1Char('"') + expression + QLatin1Char('"'); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index d8da387878..2303539194 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -52,7 +52,6 @@ #include <private/qflagpointer_p.h> #include <private/qdeletewatcher_p.h> #include <private/qpointervaluepair_p.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE @@ -60,8 +59,7 @@ QT_BEGIN_NAMESPACE class QQmlExpression; class QString; class QQmlExpressionPrivate : public QObjectPrivate, - public QQmlJavaScriptExpression, - public QQmlAbstractExpression + public QQmlJavaScriptExpression { Q_DECLARE_PUBLIC(QQmlExpression) public: @@ -82,16 +80,12 @@ public: bool expressionFunctionValid:1; - // "Inherited" from QQmlJavaScriptExpression - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); + // Inherited from QQmlJavaScriptExpression + virtual QString expressionIdentifier(); virtual void expressionChanged(); QString expression; - QV4::PersistentValue qmlscope; - QV4::PersistentValue function; - QString url; // This is a QString for a reason. QUrls are slooooooow... quint16 line; quint16 column; diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 5a54609e12..87ee8078f4 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -169,6 +169,7 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa } // namespace +#ifndef QT_NO_LIBRARY struct RegisteredPlugin { QString uri; QPluginLoader* loader; @@ -193,6 +194,7 @@ void qmlClearEnginePlugins() } typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair; +#endif class QQmlImportNamespace { @@ -292,9 +294,10 @@ public: const QString &uri, const QString &url, int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence = false); - +#ifndef QT_NO_LIBRARY bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QString &qmldirPath, QList<QQmlError> *errors); +#endif }; /*! @@ -826,6 +829,7 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr } +#ifndef QT_NO_LIBRARY /*! Get all static plugins that are QML plugins and has a meta data URI that begins with \a uri. Note that if e.g uri == "a", and different plugins have meta data "a", "a.2.1", "a.b.c", all @@ -869,6 +873,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res } return true; } +#endif /*! Import an extension defined by a qmldir file. @@ -995,6 +1000,13 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } #else + Q_UNUSED(qmldirFilePath); + Q_UNUSED(uri); + Q_UNUSED(vmaj); + Q_UNUSED(vmin); + Q_UNUSED(database); + Q_UNUSED(qmldir); + Q_UNUSED(errors); return false; #endif // QT_NO_LIBRARY return true; @@ -1931,6 +1943,12 @@ 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 } @@ -2011,6 +2029,11 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr return true; #else + Q_UNUSED(filePath); + Q_UNUSED(uri); + Q_UNUSED(typeNamespace); + Q_UNUSED(vmaj); + Q_UNUSED(errors); return false; #endif } diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 02bd1c4b83..5f30eac066 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -35,7 +35,7 @@ #include <private/qqmlexpression_p.h> #include <private/qqmlcontextwrapper_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4errorobject_p.h> @@ -83,13 +83,22 @@ void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionEngine *engine) } -QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v) -: m_vtable(v) +QQmlJavaScriptExpression::QQmlJavaScriptExpression() + : m_error(0), + m_context(0), + m_prevExpression(0), + m_nextExpression(0) { } QQmlJavaScriptExpression::~QQmlJavaScriptExpression() { + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + } + clearGuards(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = 0; @@ -106,40 +115,62 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged() clearGuards(); } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - const QV4::Value &function, bool *isUndefined) +void QQmlJavaScriptExpression::setContext(QQmlContextData *context) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(context->engine); + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + m_prevExpression = 0; + m_nextExpression = 0; + } + + m_context = context; + + if (context) { + m_nextExpression = context->expressions; + if (m_nextExpression) + m_nextExpression->m_prevExpression = &m_nextExpression; + m_prevExpression = &context->expressions; + context->expressions = this; + } +} + +void QQmlJavaScriptExpression::refresh() +{ +} + +QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined) +{ + QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine); QV4::Scope scope(v4); QV4::ScopedCallData callData(scope); - return evaluate(context, function, callData, isUndefined); + return evaluate(callData, isUndefined); } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - const QV4::Value &function, - QV4::CallData *callData, - bool *isUndefined) +QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined) { - Q_ASSERT(context && context->engine); + Q_ASSERT(m_context && m_context->engine); - if (function.isUndefined()) { + QV4::Value *f = m_function.valueRef(); + if (!f || f->isUndefined()) { if (isUndefined) *isUndefined = true; return QV4::Encode::undefined(); } - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine); // All code that follows must check with watcher before it accesses data members // incase we have been deleted. DeleteWatcher watcher(this); Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty()); - GuardCapture capture(context->engine, this, &watcher); + QQmlPropertyCapture capture(m_context->engine, this, &watcher); - QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture; - ep->propertyCapture = notifyOnValueChanged()?&capture:0; + QQmlPropertyCapture *lastPropertyCapture = ep->propertyCapture; + ep->propertyCapture = notifyOnValueChanged() ? &capture : 0; if (notifyOnValueChanged()) @@ -148,14 +179,14 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue()); - callData->thisObject = v4->globalObject(); + callData->thisObject = v4->globalObject; if (scopeObject()) { QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject())); if (value->isObject()) callData->thisObject = value; } - result = function.asFunctionObject()->call(callData); + result = f->as<QV4::FunctionObject>()->call(callData); if (scope.hasException()) { if (watcher.wasDeleted()) scope.engine->catchException(); // ignore exception @@ -178,7 +209,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, capture.errorString = 0; } - while (Guard *g = capture.guards.takeFirst()) + while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst()) g->Delete(); ep->propertyCapture = lastPropertyCapture; @@ -186,7 +217,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, return result->asReturnedValue(); } -void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) +void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) { if (watcher->wasDeleted()) return; @@ -196,13 +227,13 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) while (!guards.isEmpty() && !guards.first()->isConnected(n)) guards.takeFirst()->Delete(); - Guard *g = 0; + QQmlJavaScriptExpressionGuard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(n)); } else { - g = Guard::New(expression, engine); + g = QQmlJavaScriptExpressionGuard::New(expression, engine); g->connect(n); } @@ -213,7 +244,7 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) { if (watcher->wasDeleted()) return; @@ -223,7 +254,7 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, if (!errorString) { errorString = new QStringList; QString preamble = QLatin1String("QQmlExpression: Expression ") + - expression->m_vtable->expressionIdentifier(expression) + + expression->expressionIdentifier() + QLatin1String(" depends on non-NOTIFYable properties:"); errorString->append(preamble); } @@ -242,13 +273,13 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, while (!guards.isEmpty() && !guards.first()->isConnected(o, n)) guards.takeFirst()->Delete(); - Guard *g = 0; + QQmlJavaScriptExpressionGuard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(o, n)); } else { - g = Guard::New(expression, engine); + g = QQmlJavaScriptExpressionGuard::New(expression, engine); g->connect(o, n, engine); } @@ -258,31 +289,31 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, void QQmlJavaScriptExpression::clearError() { - if (m_vtable.hasValue()) { - m_vtable.value().clearError(); - m_vtable.value().removeError(); - } + if (m_error) + delete m_error; + m_error = 0; } QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const { Q_UNUSED(engine); - if (m_vtable.hasValue()) - return m_vtable.constValue()->error(); + if (m_error) + return m_error->error(); else return QQmlError(); } QQmlDelayedError *QQmlJavaScriptExpression::delayedError() { - return &m_vtable.value(); + if (!m_error) + m_error = new QQmlDelayedError; + return m_error; } QV4::ReturnedValue QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObject, - const QString &code, const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope) + const QString &code, const QString &filename, quint16 line) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -308,14 +339,11 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje ep->warning(error); return QV4::Encode::undefined(); } - if (qmlscope) - qmlscope->set(v4, qmlScopeObject); return result->asReturnedValue(); } -QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, QObject *qmlScope, - const QString &code, const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope) +void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *qmlScope, + const QString &code, const QString &filename, quint16 line) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -339,17 +367,15 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(qmlScope); ep->warning(error); - return QV4::Encode::undefined(); + result = QV4::Encode::undefined(); } - if (qmlscope) - qmlscope->set(v4, qmlScopeObject); - return result->asReturnedValue(); + m_function.set(v4, result); } void QQmlJavaScriptExpression::clearGuards() { - while (Guard *g = activeGuards.takeFirst()) + while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst()) g->Delete(); } @@ -358,7 +384,7 @@ void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **) QQmlJavaScriptExpression *expression = static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression; - expression->m_vtable->expressionChanged(expression); + expression->expressionChanged(); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 989d5a0b0d..dfcf8b2d68 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -89,23 +89,17 @@ private: QQmlDelayedError **prevError; }; -class QQmlJavaScriptExpression +class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression { public: - // Although this looks crazy, we implement our own "vtable" here, rather than relying on - // C++ virtuals, to save memory. By doing it ourselves, we can overload the storage - // location that is use for the vtable to also store the rarely used delayed error. - // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in - // memory for every expression. - struct VTable { - QString (*expressionIdentifier)(QQmlJavaScriptExpression *); - void (*expressionChanged)(QQmlJavaScriptExpression *); - }; + QQmlJavaScriptExpression(); + virtual ~QQmlJavaScriptExpression(); - QQmlJavaScriptExpression(VTable *vtable); + virtual QString expressionIdentifier() = 0; + virtual void expressionChanged() = 0; - QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::Value &function, bool *isUndefined); - QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::Value &function, QV4::CallData *callData, bool *isUndefined); + QV4::ReturnedValue evaluate(bool *isUndefined); + QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined); inline bool notifyOnValueChanged() const; @@ -115,6 +109,13 @@ public: inline QObject *scopeObject() const; inline void setScopeObject(QObject *v); + bool isValid() const { return context() != 0; } + + QQmlContextData *context() const { return m_context; } + void setContext(QQmlContextData *context); + + virtual void refresh(); + class DeleteWatcher { public: inline DeleteWatcher(QQmlJavaScriptExpression *); @@ -136,46 +137,50 @@ public: static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, - quint16 line, - QV4::PersistentValue *qmlscope = 0); - // doesn't require rewriting the expression - static QV4::ReturnedValue qmlBinding(QQmlContextData *ctxt, QObject *scope, - const QString &code, - const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope = 0); + quint16 line); protected: - ~QQmlJavaScriptExpression(); + void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); private: - typedef QQmlJavaScriptExpressionGuard Guard; + friend class QQmlContextData; + friend class QQmlPropertyCapture; friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); - struct GuardCapture : public QQmlEnginePrivate::PropertyCapture { - GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, DeleteWatcher *w) - : engine(engine), expression(e), watcher(w), errorString(0) { } - - ~GuardCapture() { - Q_ASSERT(guards.isEmpty()); - Q_ASSERT(errorString == 0); - } - - virtual void captureProperty(QQmlNotifier *); - virtual void captureProperty(QObject *, int, int); - - QQmlEngine *engine; - QQmlJavaScriptExpression *expression; - DeleteWatcher *watcher; - QFieldList<Guard, &Guard::next> guards; - QStringList *errorString; - }; - - QPointerValuePair<VTable, QQmlDelayedError> m_vtable; + QQmlDelayedError *m_error; // We store some flag bits in the following flag pointers. // activeGuards:flag1 - notifyOnValueChanged // activeGuards:flag2 - useSharedContext QBiPointer<QObject, DeleteWatcher> m_scopeObject; - QForwardFieldList<Guard, &Guard::next> activeGuards; + QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; + + QQmlContextData *m_context; + QQmlJavaScriptExpression **m_prevExpression; + QQmlJavaScriptExpression *m_nextExpression; + +protected: + QV4::PersistentValue m_function; +}; + +class QQmlPropertyCapture +{ +public: + QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w) + : engine(engine), expression(e), watcher(w), errorString(0) { } + + ~QQmlPropertyCapture() { + Q_ASSERT(guards.isEmpty()); + Q_ASSERT(errorString == 0); + } + + void captureProperty(QQmlNotifier *); + void captureProperty(QObject *, int, int); + + QQmlEngine *engine; + QQmlJavaScriptExpression *expression; + QQmlJavaScriptExpression::DeleteWatcher *watcher; + QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards; + QStringList *errorString; }; QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e) @@ -222,18 +227,18 @@ void QQmlJavaScriptExpression::setScopeObject(QObject *v) bool QQmlJavaScriptExpression::hasError() const { - return m_vtable.hasValue() && m_vtable.constValue()->isValid(); + return m_error && m_error->isValid(); } bool QQmlJavaScriptExpression::hasDelayedError() const { - return m_vtable.hasValue(); + return m_error; } QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e) -: expression(e), next(0) + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard), + expression(e), next(0) { - setCallback(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard); } QQmlJavaScriptExpressionGuard * diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index bcb1e72f0b..e9ecefb56d 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -92,13 +92,13 @@ QVariant QmlListWrapper::toVariant() const } -ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlListWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlListWrapper>()); - QmlListWrapper *w = static_cast<QmlListWrapper *>(m); + const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); - if (name->equals(v4->id_length) && !w->d()->object.isNull()) { + if (name->equals(v4->id_length()) && !w->d()->object.isNull()) { quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; return Primitive::fromUInt32(count).asReturnedValue(); } @@ -110,12 +110,12 @@ ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) return Object::get(m, name, hasProperty); } -ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_UNUSED(hasProperty); Q_ASSERT(m->as<QmlListWrapper>()); - QmlListWrapper *w = static_cast<QmlListWrapper *>(m); + const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index 3590bcb1c9..7e305b9e43 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -50,7 +50,7 @@ #include <QtQml/qqmllist.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -81,8 +81,8 @@ struct Q_QML_EXPORT QmlListWrapper : Object QVariant toVariant() const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); }; diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 62b5b76ede..7f49798da6 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -65,13 +65,13 @@ static bool isLocaleObject(const QV4::Value &val) void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleTimeString"), method_fromLocaleTimeString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleDateString"), method_fromLocaleDateString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleTimeString"), method_fromLocaleTimeString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleDateString"), method_fromLocaleDateString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); } QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx) @@ -81,7 +81,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ct QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->thisObject().asDateObject(); + QV4::DateObject *date = ctx->thisObject().as<DateObject>(); if (!date) return QV4::DatePrototype::method_toLocaleString(ctx); @@ -125,7 +125,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->thisObject().asDateObject(); + QV4::DateObject *date = ctx->thisObject().as<DateObject>(); if (!date) return QV4::DatePrototype::method_toLocaleTimeString(ctx); @@ -170,7 +170,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext QV4::Scope scope(ctx); - QV4::DateObject *dateObj = ctx->thisObject().asDateObject(); + QV4::DateObject *dateObj = ctx->thisObject().as<DateObject>(); if (!dateObj) return QV4::DatePrototype::method_toLocaleDateString(ctx); @@ -347,9 +347,9 @@ QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *c void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->numberPrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - engine->numberPrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); - engine->numberCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); + engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); + engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); } QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx) @@ -815,15 +815,15 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine) { - engine->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); + engine->stringPrototype()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); } QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx) { - if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].asStringObject())) + if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].as<StringObject>())) return QV4::StringPrototype::method_localeCompare(ctx); - if (!ctx->thisObject().isString() && !ctx->thisObject().asStringObject()) + if (!ctx->thisObject().isString() && !ctx->thisObject().as<StringObject>()) return QV4::StringPrototype::method_localeCompare(ctx); QString thisString = ctx->thisObject().toQStringNoThrow(); diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index d4436482cf..cb9fe9bbef 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -74,10 +74,6 @@ private: class Q_AUTOTEST_EXPORT QQmlLocale { Q_GADGET - Q_ENUMS(MeasurementSystem) - Q_ENUMS(FormatType) - Q_ENUMS(CurrencySymbolFormat) - Q_ENUMS(DayOfWeek) public: ~QQmlLocale(); @@ -88,16 +84,19 @@ public: ImperialUSSystem = QLocale::ImperialUSSystem, ImperialUKSystem = QLocale::ImperialUKSystem }; + Q_ENUM(MeasurementSystem) enum FormatType { LongFormat = QLocale::LongFormat, ShortFormat = QLocale::ShortFormat, NarrowFormat = QLocale::NarrowFormat }; + Q_ENUM(FormatType) enum CurrencySymbolFormat { CurrencyIsoCode = QLocale::CurrencyIsoCode, CurrencySymbol = QLocale::CurrencySymbol, CurrencyDisplayName = QLocale::CurrencyDisplayName }; + Q_ENUM(CurrencySymbolFormat) // Qt defines Sunday as 7, but JS Date assigns Sunday 0 enum DayOfWeek { Sunday = 0, @@ -108,6 +107,7 @@ public: Friday = Qt::Friday, Saturday = Qt::Saturday }; + Q_ENUM(DayOfWeek) static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName); static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale); @@ -137,7 +137,7 @@ struct QQmlLocaleData : public QV4::Object V4_NEEDS_DESTROY static QLocale *getThisLocale(QV4::CallContext *ctx) { - QV4::Object *o = ctx->thisObject().asObject(); + QV4::Object *o = ctx->thisObject().as<Object>(); QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0; if (!thisObject) { ctx->engine()->throwTypeError(); diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp index cdd60e2dec..531666340b 100644 --- a/src/qml/qml/qqmlmemoryprofiler.cpp +++ b/src/qml/qml/qqmlmemoryprofiler.cpp @@ -63,11 +63,13 @@ static qmlmemprofile_pop_location *memprofile_pop_location; static qmlmemprofile_save *memprofile_save; static qmlmemprofile_is_enabled *memprofile_is_enabled; +#ifndef QT_NO_LIBRARY extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); +#endif static bool openLibrary() { -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) && !defined(QT_NO_LIBRARY) if (state == Unloaded) { memprofile_stats = (qmlmemprofile_stats *) qt_linux_find_symbol_sys("qmlmemprofile_stats"); memprofile_clear = (qmlmemprofile_clear *) qt_linux_find_symbol_sys("qmlmemprofile_clear"); diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 2f7834fa41..55df65e607 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1107,7 +1107,9 @@ void qmlClearTypeRegistrations() // Declared in qqml.h data->uriToModule.clear(); QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types +#ifndef QT_NO_LIBRARY qmlClearEnginePlugins(); +#endif } int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) @@ -1437,8 +1439,8 @@ bool QQmlMetaType::isAnyModule(const QString &uri) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin(); - iter != data->uriToModule.end(); ++iter) { + for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin(); + iter != data->uriToModule.cend(); ++iter) { if ((*iter)->module() == uri) return true; } @@ -1715,7 +1717,7 @@ QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStrin QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); - while (it != data->nameToType.end() && it.key() == name) { + while (it != data->nameToType.cend() && it.key() == name) { // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor)) return (*it); @@ -1749,7 +1751,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStri QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); - while (it != data->metaObjectToType.end() && it.key() == metaObject) { + while (it != data->metaObjectToType.cend() && it.key() == metaObject) { QQmlType *t = *it; if (version_major < 0 || module.isEmpty() || t->availableInVersion(module, version_major,version_minor)) return t; @@ -1820,8 +1822,9 @@ QList<QString> QQmlMetaType::qmlTypeNames() QQmlMetaTypeData *data = metaTypeData(); QList<QString> names; - QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin(); - while (it != data->nameToType.end()) { + names.reserve(data->nameToType.count()); + QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin(); + while (it != data->nameToType.cend()) { names += (*it)->qmlTypeName(); ++it; } diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index 2a35dcda12..bd2c0e6506 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -61,9 +61,6 @@ class QQmlEngine; class QQmlNotifierEndpoint { public: - inline QQmlNotifierEndpoint(); - inline ~QQmlNotifierEndpoint(); - // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks. // To add another callback, extend this enum and add the callback to the top // of qqmlnotifier.cpp. Four bits are reserved for the callback, so there can @@ -75,7 +72,8 @@ public: QQmlVMEMetaObjectEndpoint = 3 }; - inline void setCallback(Callback c) { callback = c; } + inline QQmlNotifierEndpoint(Callback callback); + inline ~QQmlNotifierEndpoint(); inline bool isConnected(); inline bool isConnected(QObject *source, int sourceSignal); @@ -88,6 +86,8 @@ public: inline bool isNotifying() const; inline void cancelNotify(); + inline int signalIndex() const { return sourceSignal; } + private: friend class QQmlData; friend class QQmlNotifier; @@ -136,8 +136,8 @@ void QQmlNotifier::notify() if (endpoints) emitNotify(endpoints, args); } -QQmlNotifierEndpoint::QQmlNotifierEndpoint() -: senderPtr(0), callback(None), sourceSignal(-1), next(0), prev(0) +QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback) +: senderPtr(0), callback(callback), sourceSignal(-1), next(0), prev(0) { } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 3c2f3690b9..0b977f2551 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -62,14 +62,6 @@ struct ActiveOCRestorer }; } -static void removeBindingOnProperty(QObject *o, int index) -{ - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0); - if (binding) binding->destroy(); -} - QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext) : phase(Startup) , compiledData(compiledData) @@ -137,11 +129,6 @@ QQmlObjectCreator::~QQmlObjectCreator() { QQmlObjectCreatorRecursionWatcher watcher(this); } - for (int i = 0; i < sharedState->allCreatedBindings.count(); ++i) { - QQmlAbstractBinding *b = sharedState->allCreatedBindings.at(i); - if (b) - b->m_mePtr = 0; - } for (int i = 0; i < sharedState->allParserStatusCallbacks.count(); ++i) { QQmlParserStatus *ps = sharedState->allParserStatusCallbacks.at(i); if (ps) @@ -660,15 +647,12 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) // ### this is best done through type-compile-time binding skip lists. if (_valueTypeProperty) { - QQmlAbstractBinding *binding = - QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex, -1); + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex); - if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) { - QQmlPropertyPrivate::setBinding(_bindingTarget, _valueTypeProperty->coreIndex, -1, 0); - binding->destroy(); + if (binding && !binding->isValueTypeProxy()) { + QQmlPropertyPrivate::removeBinding(_bindingTarget, _valueTypeProperty->coreIndex); } else if (binding) { - QQmlValueTypeProxyBinding *proxy = - static_cast<QQmlValueTypeProxyBinding *>(binding); + QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding); if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; @@ -731,7 +715,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con // ### resolve this at compile time if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : QQmlBinding::Invalid; + ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; ss.d.data()->columnNumber = binding->location.column; ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; @@ -800,7 +784,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) && !_valueTypeProperty) - removeBindingOnProperty(_bindingTarget, property->coreIndex); + QQmlPropertyPrivate::removeBinding(_bindingTarget, property->coreIndex); if (binding->type == QV4::CompiledData::Binding::Type_Script) { QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; @@ -828,18 +812,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_valueTypeProperty) targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); - sharedState->allCreatedBindings.push(qmlBinding); - qmlBinding->m_mePtr = &sharedState->allCreatedBindings.top(); + sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); - qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context); + qmlBinding->setTarget(_bindingTarget, targetCorePropertyData); if (targetCorePropertyData.isAlias()) { - QQmlAbstractBinding *old = - QQmlPropertyPrivate::setBindingNoEnable(_bindingTarget, - targetCorePropertyData.coreIndex, - targetCorePropertyData.getValueTypeCoreIndex(), - qmlBinding); - if (old) { old->destroy(); } + QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable); } else { qmlBinding->addToObject(); @@ -1011,7 +989,7 @@ QV4::Heap::ExecutionContext *QQmlObjectCreator::currentQmlContext() { if (!_qmlBindingWrapper->objectValue()) { QV4::Scope valueScope(v4); - QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); + QV4::Scoped<QV4::QmlContextWrapper> qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); QV4::ScopedContext global(valueScope, v4->rootContext()); *_qmlBindingWrapper = v4->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScope); } @@ -1124,7 +1102,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QBitArray bindingsToSkip; if (customParser) { - QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index); + QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index); if (customParserBindings != compiledData->customParserBindings.constEnd()) { customParser->imports = compiledData->importCache; @@ -1183,13 +1161,14 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); while (!sharedState->allCreatedBindings.isEmpty()) { - QQmlAbstractBinding *b = sharedState->allCreatedBindings.pop(); - if (!b) + QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop(); + Q_ASSERT(b); + // skip, if b is not added to an object + if (!b->isAddedToObject()) continue; - b->m_mePtr = 0; - QQmlData *data = QQmlData::get(b->object()); + QQmlData *data = QQmlData::get(b->targetObject()); Q_ASSERT(data); - data->clearPendingBindingBit(b->propertyIndex()); + data->clearPendingBindingBit(b->targetPropertyIndex()); b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); @@ -1299,7 +1278,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QBitArray bindingSkipList = bindingsToSkip; { - QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.find(_compiledObjectIndex); + QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex); if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { if (bindingSkipList.isEmpty()) bindingSkipList.resize(deferredBindings->count()); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 60fefe494f..c88c15b525 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -55,7 +55,7 @@ struct QQmlObjectCreatorSharedState : public QSharedData { QQmlContextData *rootContext; QQmlContextData *creationContext; - QFiniteStack<QQmlAbstractBinding*> allCreatedBindings; + QFiniteStack<QQmlAbstractBinding::Ptr> allCreatedBindings; QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks; QFiniteStack<QPointer<QObject> > allCreatedObjects; QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase. diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index fc24b15fd2..c6d2d44ee1 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -277,8 +277,8 @@ void QQmlOpenMetaObject::setValue(int id, const QVariant &value) QVariant QQmlOpenMetaObject::value(const QByteArray &name) const { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); - if (iter == d->type->d->names.end()) + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); + if (iter == d->type->d->names.cend()) return QVariant(); return d->getData(*iter); @@ -286,8 +286,8 @@ QVariant QQmlOpenMetaObject::value(const QByteArray &name) const QVariant &QQmlOpenMetaObject::operator[](const QByteArray &name) { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); - Q_ASSERT(iter != d->type->d->names.end()); + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); + Q_ASSERT(iter != d->type->d->names.cend()); return d->getData(*iter); } @@ -299,10 +299,10 @@ QVariant &QQmlOpenMetaObject::operator[](int id) bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); int id = -1; - if (iter == d->type->d->names.end()) { + if (iter == d->type->d->names.cend()) { id = createProperty(name.constData(), "") - d->type->d->propertyOffset; } else { id = *iter; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index ae452b727e..414bf8fe0f 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -55,6 +55,7 @@ #include <private/qmetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <QtCore/qdebug.h> +#include <cmath> Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<qreal>) @@ -699,8 +700,7 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) if (!that.d || !that.isProperty() || !that.d->object) return 0; - return binding(that.d->object, that.d->core.coreIndex, - that.d->core.getValueTypeCoreIndex()); + return binding(that.d->object, that.d->core.encodedIndex()); } /*! @@ -716,65 +716,96 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) \a flags is passed through to the binding and is used for the initial update (when the binding sets the initial value, it will use these flags for the write). */ -QQmlAbstractBinding * -QQmlPropertyPrivate::setBinding(const QQmlProperty &that, - QQmlAbstractBinding *newBinding, - WriteFlags flags) +void +QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *newBinding) { + if (!newBinding) { + removeBinding(that); + return; + } + if (!that.d || !that.isProperty() || !that.d->object) { - if (newBinding) - newBinding->destroy(); - return 0; + if (!newBinding->ref) + delete newBinding; + return; } + setBinding(newBinding); +} + +static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None) +{ + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); - if (newBinding) { - // In the case that the new binding is provided, we must target the property it - // is associated with. If we don't do this, retargetBinding() can fail. - QObject *object = newBinding->object(); - int pi = newBinding->propertyIndex(); + QQmlData *data = QQmlData::get(object, false); - int core; - int vt = QQmlPropertyData::decodeValueTypePropertyIndex(pi, &core); + if (!data || !data->hasBindingBit(coreIndex)) + return; - return setBinding(object, core, vt, newBinding, flags); - } else { - return setBinding(that.d->object, that.d->core.coreIndex, - that.d->core.getValueTypeCoreIndex(), - newBinding, flags); - } + QQmlAbstractBinding::Ptr oldBinding; + oldBinding = data->bindings; + + while (oldBinding && oldBinding->targetPropertyIndex() != coreIndex) + oldBinding = oldBinding->nextBinding(); + + if (!oldBinding) + return; + + if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy()) + oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index); + + if (!oldBinding) + return; + + if (!(flags & QQmlPropertyPrivate::DontEnable)) + oldBinding->setEnabled(false, 0); + oldBinding->removeFromObject(); +} + +void QQmlPropertyPrivate::removeBinding(QQmlAbstractBinding *b) +{ + removeBinding(b->targetObject(), b->targetPropertyIndex()); +} + +void QQmlPropertyPrivate::removeBinding(QObject *o, int index) +{ + Q_ASSERT(o); + + QObject *target; + int targetIndex; + findAliasTarget(o, index, &target, &targetIndex); + removeOldBinding(target, targetIndex); +} + +void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that) +{ + if (!that.d || !that.isProperty() || !that.d->object) + return; + + removeBinding(that.d->object, that.d->core.encodedIndex()); } QQmlAbstractBinding * -QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) +QQmlPropertyPrivate::binding(QObject *object, int index) { QQmlData *data = QQmlData::get(object); if (!data) return 0; - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + findAliasTarget(object, index, &object, &index); - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1) - return 0; - - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return binding(aObject, aCoreIndex, aValueTypeIndex); - } + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); if (!data->hasBindingBit(coreIndex)) return 0; QQmlAbstractBinding *binding = data->bindings; - while (binding && binding->propertyIndex() != coreIndex) + while (binding && binding->targetPropertyIndex() != coreIndex) binding = binding->nextBinding(); if (binding && valueTypeIndex != -1) { - if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) { + if (binding->isValueTypeProxy()) { int index = QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeIndex); binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); } @@ -786,11 +817,11 @@ QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, QObject **targetObject, int *targetBindingIndex) { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); - QQmlData *data = QQmlData::get(object, false); if (data) { + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); + QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { @@ -817,119 +848,30 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, *targetBindingIndex = bindingIndex; } -QQmlAbstractBinding * -QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex, - QQmlAbstractBinding *newBinding, WriteFlags flags) -{ - QQmlData *data = QQmlData::get(object, 0 != newBinding); - QQmlAbstractBinding *binding = 0; - - if (data) { - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); - - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { - if (newBinding) newBinding->destroy(); - return 0; - } - - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags); - } - } - - if (data && data->hasBindingBit(coreIndex)) { - binding = data->bindings; - - while (binding && binding->propertyIndex() != coreIndex) - binding = binding->nextBinding(); - } - - int index = coreIndex; - if (valueTypeIndex != -1) - index = QQmlPropertyData::encodeValueTypePropertyIndex(index, valueTypeIndex); - - if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) - binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); - - if (binding) { - binding->removeFromObject(); - binding->setEnabled(false, 0); - } - - if (newBinding) { - if (newBinding->propertyIndex() != index || newBinding->object() != object) - newBinding->retargetBinding(object, index); - - Q_ASSERT(newBinding->propertyIndex() == index); - Q_ASSERT(newBinding->object() == object); - - newBinding->addToObject(); - newBinding->setEnabled(true, flags); - } - - return binding; -} -QQmlAbstractBinding * -QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex, - QQmlAbstractBinding *newBinding) +void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, WriteFlags writeFlags) { - QQmlData *data = QQmlData::get(object, 0 != newBinding); - QQmlAbstractBinding *binding = 0; + Q_ASSERT(binding); - if (data) { - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); - - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { - if (newBinding) newBinding->destroy(); - return 0; - } + QObject *object = binding->targetObject(); + int index = binding->targetPropertyIndex(); - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding); - } - } - - if (data && data->hasBindingBit(coreIndex)) { - binding = data->bindings; - - while (binding && binding->propertyIndex() != coreIndex) - binding = binding->nextBinding(); +#ifndef QT_NO_DEBUG + int coreIndex; + QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); + QQmlData *data = QQmlData::get(object, true); + if (data->propertyCache) { + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData && !propertyData->isAlias()); } +#endif - int index = coreIndex; - if (valueTypeIndex != -1) - index = QQmlPropertyData::encodeValueTypePropertyIndex(index, valueTypeIndex); - - if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) - binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); - - if (binding) - binding->removeFromObject(); - - if (newBinding) { - if (newBinding->propertyIndex() != index || newBinding->object() != object) - newBinding->retargetBinding(object, index); - - Q_ASSERT(newBinding->propertyIndex() == index); - Q_ASSERT(newBinding->object() == object); + removeOldBinding(object, index, flags); - newBinding->addToObject(); - } + binding->addToObject(); + if (!(flags & DontEnable)) + binding->setEnabled(true, writeFlags); - return binding; } /*! @@ -946,9 +888,9 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) if (!data) return 0; - QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + QQmlBoundSignal *signalHandler = data->signalHandlers; - while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex()) + while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex()) signalHandler = signalHandler->m_nextSignal; if (signalHandler) @@ -959,48 +901,41 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) /*! Set the signal expression associated with this signal property to \a expr. - Returns the existing signal expression (if any), otherwise null. - - A reference to \a expr will be added by QML. Ownership of the return value - reference is assumed by the caller. + A reference to \a expr will be added by QML. */ -QQmlBoundSignalExpressionPointer -QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, - QQmlBoundSignalExpression *expr) +void QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr) { if (expr) expr->addref(); - return QQmlPropertyPrivate::takeSignalExpression(that, expr); + QQmlPropertyPrivate::takeSignalExpression(that, expr); } /*! Set the signal expression associated with this signal property to \a expr. - Returns the existing signal expression (if any), otherwise null. - - Ownership of \a expr transfers to QML. Ownership of the return value - reference is assumed by the caller. + Ownership of \a expr transfers to QML. */ -QQmlBoundSignalExpressionPointer -QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, +void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr) { if (!(that.type() & QQmlProperty::SignalProperty)) { if (expr) expr->release(); - return 0; + return; } QQmlData *data = QQmlData::get(that.d->object, 0 != expr); if (!data) - return 0; + return; - QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + QQmlBoundSignal *signalHandler = data->signalHandlers; - while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex()) + while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex()) signalHandler = signalHandler->m_nextSignal; - if (signalHandler) - return signalHandler->takeExpression(expr); + if (signalHandler) { + signalHandler->takeExpression(expr); + return; + } if (expr) { int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex(); @@ -1008,7 +943,6 @@ QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, expr->context()->engine); signal->takeExpression(expr); } - return 0; } /*! @@ -1125,7 +1059,7 @@ QVariant QQmlPropertyPrivate::readValueProperty() } // helper function to allow assignment / binding to QList<QUrl> properties. -static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context) +QVariant QQmlPropertyPrivate::resolvedUrlSequence(const QVariant &value, QQmlContextData *context) { QList<QUrl> urls; if (value.userType() == qMetaTypeId<QUrl>()) { @@ -1138,16 +1072,22 @@ static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *cont urls = value.value<QList<QUrl> >(); } else if (value.userType() == qMetaTypeId<QStringList>()) { QStringList urlStrings = value.value<QStringList>(); - for (int i = 0; i < urlStrings.size(); ++i) + const int urlStringsSize = urlStrings.size(); + urls.reserve(urlStringsSize); + for (int i = 0; i < urlStringsSize; ++i) urls.append(QUrl(urlStrings.at(i))); } else if (value.userType() == qMetaTypeId<QList<QString> >()) { QList<QString> urlStrings = value.value<QList<QString> >(); - for (int i = 0; i < urlStrings.size(); ++i) + const int urlStringsSize = urlStrings.size(); + urls.reserve(urlStringsSize); + for (int i = 0; i < urlStringsSize; ++i) urls.append(QUrl(urlStrings.at(i))); } // note: QList<QByteArray> is not currently supported. QList<QUrl> resolvedUrls; - for (int i = 0; i < urls.size(); ++i) { + const int urlsSize = urls.size(); + resolvedUrls.reserve(urlsSize); + for (int i = 0; i < urlsSize; ++i) { QUrl u = urls.at(i); if (context && u.isRelative() && !u.isEmpty()) u = context->resolvedUrl(u); @@ -1210,12 +1150,8 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlContextData *context, WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & DontRemoveBinding) && object) { - QQmlAbstractBinding *binding = setBinding(object, core.coreIndex, - core.getValueTypeCoreIndex(), - 0, flags); - if (binding) binding->destroy(); - } + if (!(flags & DontRemoveBinding) && object) + removeBinding(object, core.encodedIndex()); bool rv = false; if (core.isValueTypeVirtual()) { @@ -1255,7 +1191,7 @@ bool QQmlPropertyPrivate::write(QObject *object, // Enum values come through the script engine as doubles if (value.userType() == QVariant::Double) { double integral; - double fractional = modf(value.toDouble(), &integral); + double fractional = std::modf(value.toDouble(), &integral); if (qFuzzyIsNull(fractional)) v.convert(QVariant::Int); } @@ -1475,165 +1411,6 @@ bool QQmlPropertyPrivate::write(QObject *object, return true; } -// Returns true if successful, false if an error description was set on expression -bool QQmlPropertyPrivate::writeBinding(QObject *object, - const QQmlPropertyData &core, - QQmlContextData *context, - QQmlJavaScriptExpression *expression, - const QV4::Value &result, bool isUndefined, - WriteFlags flags) -{ - Q_ASSERT(object); - Q_ASSERT(core.coreIndex != -1); - - QQmlEngine *engine = context->engine; - QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); - -#define QUICK_STORE(cpptype, conversion) \ - { \ - cpptype o = (conversion); \ - int status = -1; \ - void *argv[] = { &o, 0, &status, &flags }; \ - QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \ - return true; \ - } \ - - - if (!isUndefined && !core.isValueTypeVirtual()) { - switch (core.propType) { - case QMetaType::Int: - if (result.isInteger()) - QUICK_STORE(int, result.integerValue()) - else if (result.isNumber()) - QUICK_STORE(int, result.doubleValue()) - break; - case QMetaType::Double: - if (result.isNumber()) - QUICK_STORE(double, result.asDouble()) - break; - case QMetaType::Float: - if (result.isNumber()) - QUICK_STORE(float, result.asDouble()) - break; - case QMetaType::QString: - if (result.isString()) - QUICK_STORE(QString, result.toQStringNoThrow()) - break; - default: - if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { - if (vtw->d()->valueType->typeId == core.propType) { - return vtw->write(object, core.coreIndex); - } - } - break; - } - } -#undef QUICK_STORE - - int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType; - - QQmlJavaScriptExpression::DeleteWatcher watcher(expression); - - QVariant value; - bool isVarProperty = core.isVarProperty(); - - if (isUndefined) { - } else if (core.isQList()) { - value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); - } else if (result.isNull() && core.isQObject()) { - value = QVariant::fromValue((QObject *)0); - } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { - value = resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context); - } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { - value = QV8Engine::getV4(v8engine)->toVariant(result, type); - } - - if (expression->hasError()) { - return false; - } else if (isVarProperty) { - QV4::FunctionObject *f = result.asFunctionObject(); - if (f && f->isBinding()) { - // we explicitly disallow this case to avoid confusion. Users can still store one - // in an array in a var property if they need to, but the common case is user error. - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - expression->delayedError()->setErrorObject(object); - return false; - } - - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmemo); - vmemo->setVMEProperty(core.coreIndex, result); - } else if (isUndefined && core.isResettable()) { - void *args[] = { 0 }; - QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args); - } else if (isUndefined && type == qMetaTypeId<QVariant>()) { - writeValueProperty(object, core, QVariant(), context, flags); - } else if (type == qMetaTypeId<QJSValue>()) { - QV4::FunctionObject *f = result.asFunctionObject(); - if (f && f->isBinding()) { - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - expression->delayedError()->setErrorObject(object); - return false; - } - writeValueProperty(object, core, QVariant::fromValue( - QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), - context, flags); - } else if (isUndefined) { - QString errorStr = QLatin1String("Unable to assign [undefined] to "); - if (!QMetaType::typeName(type)) - errorStr += QLatin1String("[unknown property type]"); - else - errorStr += QLatin1String(QMetaType::typeName(type)); - expression->delayedError()->setErrorDescription(errorStr); - expression->delayedError()->setErrorObject(object); - return false; - } else if (QV4::FunctionObject *f = result.asFunctionObject()) { - if (f->isBinding()) - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - else - expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); - expression->delayedError()->setErrorObject(object); - return false; - } else if (!writeValueProperty(object, core, value, context, flags)) { - - if (watcher.wasDeleted()) - return true; - - const char *valueType = 0; - const char *propertyType = 0; - - if (value.userType() == QMetaType::QObjectStar) { - if (QObject *o = *(QObject **)value.constData()) { - valueType = o->metaObject()->className(); - - QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); - if (!propertyMetaObject.isNull()) - propertyType = propertyMetaObject.className(); - } - } else if (value.userType() != QVariant::Invalid) { - if (value.userType() == QMetaType::VoidStar) - valueType = "null"; - else - valueType = QMetaType::typeName(value.userType()); - } - - if (!valueType) - valueType = "undefined"; - if (!propertyType) - propertyType = QMetaType::typeName(type); - if (!propertyType) - propertyType = "[unknown property type]"; - - expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") + - QLatin1String(valueType) + - QLatin1String(" to ") + - QLatin1String(propertyType)); - expression->delayedError()->setErrorObject(object); - return false; - } - - return true; -} QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType) { diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 98e310ebce..51a1db7b90 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE class QQmlContext; class QQmlEnginePrivate; class QQmlJavaScriptExpression; + class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount { public: @@ -103,15 +104,18 @@ public: QQmlContextData *, WriteFlags flags = 0); static void findAliasTarget(QObject *, int, QObject **, int *); - static QQmlAbstractBinding *setBinding(QObject *, int coreIndex, - int valueTypeIndex /* -1 */, - QQmlAbstractBinding *, - WriteFlags flags = DontRemoveBinding); - static QQmlAbstractBinding *setBindingNoEnable(QObject *, int coreIndex, - int valueTypeIndex /* -1 */, - QQmlAbstractBinding *); - static QQmlAbstractBinding *binding(QObject *, int coreIndex, - int valueTypeIndex /* -1 */); + enum BindingFlag { + None = 0, + DontEnable = 0x1 + }; + Q_DECLARE_FLAGS(BindingFlags, BindingFlag) + + static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, WriteFlags writeFlags = DontRemoveBinding); + + static void removeBinding(const QQmlProperty &that); + static void removeBinding(QObject *o, int index); + static void removeBinding(QQmlAbstractBinding *b); + static QQmlAbstractBinding *binding(QObject *, int index); static QQmlPropertyData saveValueType(const QQmlPropertyData &, const QMetaObject *, int, @@ -128,20 +132,13 @@ public: // "Public" (to QML) methods static QQmlAbstractBinding *binding(const QQmlProperty &that); - static QQmlAbstractBinding *setBinding(const QQmlProperty &that, - QQmlAbstractBinding *, - WriteFlags flags = DontRemoveBinding); + static void setBinding(const QQmlProperty &that, QQmlAbstractBinding *); static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that); - static QQmlBoundSignalExpressionPointer setSignalExpression(const QQmlProperty &that, + static void setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); - static QQmlBoundSignalExpressionPointer takeSignalExpression(const QQmlProperty &that, + static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); - static bool writeBinding(QObject *, const QQmlPropertyData &, - QQmlContextData *context, - QQmlJavaScriptExpression *expression, - const QV4::Value &result, bool isUndefined, - WriteFlags flags); static int valueTypeCoreIndex(const QQmlProperty &that); static int bindingIndex(const QQmlProperty &that); static int bindingIndex(const QQmlPropertyData &that); @@ -150,9 +147,12 @@ public: const QObject *receiver, int method_index, int type = 0, int *types = 0); static void flushSignal(const QObject *sender, int signal_index); + + static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags) QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index dd1f93ec00..294f3ccdf9 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -42,7 +42,7 @@ #include <private/qqmlaccessors_p.h> #include <private/qmetaobjectbuilder_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <QtCore/qdebug.h> @@ -837,7 +837,7 @@ void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) void QQmlPropertyCache::update(const QMetaObject *metaObject) { Q_ASSERT(metaObject); - Q_ASSERT(stringCache.isEmpty()); + stringCache.clear(); // Preallocate enough space in the index caches for all the properties/methods/signals that // are not cached in a parent cache so that the caches never need to be reallocated as this @@ -862,7 +862,6 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject) */ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) { - stringCache.clear(); propertyIndexCache.clear(); methodIndexCache.clear(); signalHandlerIndexCache.clear(); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 6ed9ec0d36..4d8c6dd9a5 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -54,7 +54,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE @@ -174,7 +174,6 @@ public: int propType; // When !NotFullyResolved const char *propTypeName; // When NotFullyResolved }; - int coreIndex; union { // The notify index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). @@ -208,6 +207,7 @@ public: qintptr accessorData; }; }; + int coreIndex; private: friend class QQmlPropertyData; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index d713e9ee03..408f17ffde 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -81,7 +81,7 @@ #define ASSERT_MAINTHREAD() do { if (m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in main thread"); } while (false) #define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false) -#define ASSERT_CALLBACK() do { if(!m_manager || !m_manager->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while(false) +#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false) #else @@ -1612,6 +1612,20 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) } else { QQmlTypeLoader::load(typeData, mode); } + } else if ((mode == PreferSynchronous) && QQmlFile::isSynchronous(url)) { + // this was started Asynchronous, but we need to force Synchronous + // completion now (if at all possible with this type of URL). + + if (!m_thread->isThisThread()) { + // this only works when called directly from the UI thread, but not + // when recursively called on the QML thread via resolveTypes() + + while (!typeData->isCompleteOrError()) { + unlock(); + m_thread->waitForNextMessage(); + lock(); + } + } } typeData->addref(); @@ -2114,6 +2128,7 @@ void QQmlTypeData::dataReceived(const Data &data) QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; + errors.reserve(compiler.errors.count()); foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) { QQmlError e; e.setUrl(finalUrl()); @@ -2519,8 +2534,8 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare return QV4::PersistentValue(); } - QV4::ScopedValue qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); - QV4::QmlContextWrapper::takeContextOwnership(qmlglobal); + QV4::Scoped<QV4::QmlContextWrapper> qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); + qmlglobal->takeContextOwnership(); m_program->qml.set(scope.engine, qmlglobal); m_program->run(); @@ -2594,7 +2609,7 @@ void QQmlScriptBlob::dataReceived(const Data &data) return; } if (!unit) { - unit.take(new EmptyCompilationUnit); + unit.adopt(new EmptyCompilationUnit); } irUnit.javaScriptCompilationUnit = unit; irUnit.imports = collector.imports; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d9ea273698..5be478fa65 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -60,7 +60,7 @@ #include <private/qflagpointer_p.h> #include <private/qqmlirbuilder_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4script_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index d0658f2c3c..23cc12c895 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -125,7 +125,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons const Import *i = static_cast<const Import *>(importNamespace); Q_ASSERT(i->scriptIndex == -1); - QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.find(i); + QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.constFind(i); if (it != m_namespacedImports.constEnd()) { Result r = query(*it, name); if (r.isValid()) diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 8a2118ef27..1d72b2da0d 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -124,19 +124,19 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q } -ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlTypeWrapper>()); - QV4::ExecutionEngine *v4 = static_cast<QmlTypeWrapper *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QmlTypeWrapper *>(m)->engine(); QV4::Scope scope(v4); - Scoped<QmlTypeWrapper> w(scope, static_cast<QmlTypeWrapper *>(m)); + Scoped<QmlTypeWrapper> w(scope, static_cast<const QmlTypeWrapper *>(m)); if (hasProperty) *hasProperty = true; - QQmlContextData *context = v4->v8Engine->callingContext(); + QQmlContextData *context = v4->callingQmlContext(); QObject *object = w->d()->object; @@ -240,7 +240,7 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) return; QV4::Scope scope(v4); - QQmlContextData *context = v4->v8Engine->callingContext(); + QQmlContextData *context = v4->callingQmlContext(); QQmlType *type = w->d()->type; if (type && !type->isSingleton() && w->d()->object) { diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 660d2836ff..14741a5bad 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qpointer.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -94,7 +94,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static bool isEqualTo(Managed *that, Managed *o); diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index b147266080..7ebfcd64b7 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -517,7 +517,9 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant) if ((variantList.count() % 6) == 0) { bool allRealsOk = true; QList<qreal> reals; - for (int i = 0; i < variantList.count(); i++) { + const int variantListCount = variantList.count(); + reals.reserve(variantListCount); + for (int i = 0; i < variantListCount; i++) { bool ok; const qreal real = variantList.at(i).toReal(&ok); reals.append(real); diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 2c02cc0aa1..abd73d7f35 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -209,7 +209,6 @@ struct QQmlEasingValueType { QEasingCurve v; Q_GADGET - Q_ENUMS(Type) Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL) Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL) @@ -243,6 +242,7 @@ public: SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve, Bezier = QEasingCurve::BezierSpline }; + Q_ENUM(Type) Type type() const; qreal amplitude() const; diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp index cfc9b196d2..3bc8493cbb 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -35,80 +35,42 @@ QT_BEGIN_NAMESPACE -// Used in qqmlabstractbinding.cpp -QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable = { - QQmlAbstractBinding::default_destroy<QQmlValueTypeProxyBinding>, - QQmlAbstractBinding::default_expression, - QQmlValueTypeProxyBinding::propertyIndex, - QQmlValueTypeProxyBinding::object, - QQmlValueTypeProxyBinding::setEnabled, - QQmlValueTypeProxyBinding::update, - QQmlAbstractBinding::default_retargetBinding -}; - QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index) -: QQmlAbstractBinding(ValueTypeProxy), m_object(o), m_index(index), m_bindings(0) + : QQmlAbstractBinding(), + m_bindings(0) { + m_target = o; + m_targetIndex = index; } QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding() { - QQmlAbstractBinding *binding = m_bindings; - // This must be identical to the logic in QQmlData::destroyed() + QQmlAbstractBinding *binding = m_bindings.data(); while (binding) { - QQmlAbstractBinding *next = binding->nextBinding(); binding->setAddedToObject(false); - binding->setNextBinding(0); - binding->destroy(); - binding = next; + binding = binding->nextBinding(); } } -void QQmlValueTypeProxyBinding::setEnabled(QQmlAbstractBinding *_This, - bool e, QQmlPropertyPrivate::WriteFlags flags) +void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) { - QQmlValueTypeProxyBinding *This = static_cast<QQmlValueTypeProxyBinding *>(_This); - - if (e) { - QQmlAbstractBinding *bindings = This->m_bindings; - This->recursiveEnable(bindings, flags); - } else { - QQmlAbstractBinding *bindings = This->m_bindings; - This->recursiveDisable(bindings); + QQmlAbstractBinding *b = m_bindings.data(); + while (b) { + b->setEnabled(e, flags); + b = b->nextBinding(); } } -void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags) -{ - if (!b) - return; - - recursiveEnable(b->nextBinding(), flags); - - if (b) - b->setEnabled(true, flags); -} - -void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b) -{ - if (!b) - return; - - recursiveDisable(b->nextBinding()); - - if (b) - b->setEnabled(false, 0); -} - -void QQmlValueTypeProxyBinding::update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags) +bool QQmlValueTypeProxyBinding::isValueTypeProxy() const { + return true; } QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex) { - QQmlAbstractBinding *binding = m_bindings; + QQmlAbstractBinding *binding = m_bindings.data(); - while (binding && binding->propertyIndex() != propertyIndex) + while (binding && binding->targetPropertyIndex() != propertyIndex) binding = binding->nextBinding(); return binding; @@ -119,23 +81,20 @@ Removes a collection of bindings, corresponding to the set bits in \a mask. */ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) { - QQmlAbstractBinding *binding = m_bindings; + QQmlAbstractBinding *binding = m_bindings.data(); QQmlAbstractBinding *lastBinding = 0; while (binding) { - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->propertyIndex()); + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->targetPropertyIndex()); if (valueTypeIndex != -1 && (mask & (1 << valueTypeIndex))) { QQmlAbstractBinding *remove = binding; + remove->setAddedToObject(false); binding = remove->nextBinding(); if (lastBinding == 0) m_bindings = remove->nextBinding(); else lastBinding->setNextBinding(remove->nextBinding()); - - remove->setAddedToObject(false); - remove->setNextBinding(0); - remove->destroy(); } else { lastBinding = binding; binding = binding->nextBinding(); @@ -143,24 +102,4 @@ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) } } -int QQmlValueTypeProxyBinding::propertyIndex(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlValueTypeProxyBinding *>(This)->m_index; -} - -QObject *QQmlValueTypeProxyBinding::object(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlValueTypeProxyBinding *>(This)->m_object; -} - -int QQmlValueTypeProxyBinding::propertyIndex() const -{ - return m_index; -} - -QObject *QQmlValueTypeProxyBinding::object() const -{ - return m_object; -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index 873fbb4af1..4afadfc17d 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -54,30 +54,18 @@ class QQmlValueTypeProxyBinding : public QQmlAbstractBinding public: QQmlValueTypeProxyBinding(QObject *o, int coreIndex); - int propertyIndex() const; - QObject *object() const; - - QQmlAbstractBinding *binding(int propertyIndex); - + QQmlAbstractBinding *binding(int targetPropertyIndex); void removeBindings(quint32 mask); - // "Inherited" from QQmlAbstractBinding - static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - static int propertyIndex(const QQmlAbstractBinding *); - static QObject *object(const QQmlAbstractBinding *); + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags); + virtual bool isValueTypeProxy() const; protected: ~QQmlValueTypeProxyBinding(); private: - void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - void recursiveDisable(QQmlAbstractBinding *); - friend class QQmlAbstractBinding; - QObject *m_object; - int m_index; - QQmlAbstractBinding *m_bindings; + Ptr m_bindings; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index e87d9ede77..b0ab85199d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -43,7 +43,6 @@ #include <private/qv4engine_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4variantobject_p.h> -#include <private/qv4qmlextensions_p.h> #include <private/qv4alloca_p.h> QT_BEGIN_NAMESPACE @@ -165,13 +164,13 @@ bool QQmlValueTypeReference::readReferenceValue() const void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4) { - if (v4->qmlExtensions()->valueTypeWrapperPrototype) + if (v4->valueTypeWrapperPrototype()->as<Object>()) return; Scope scope(v4); ScopedObject o(scope, v4->newObject()); - o->defineDefaultProperty(v4->id_toString, method_toString, 1); - v4->qmlExtensions()->valueTypeWrapperPrototype = o->d(); + o->defineDefaultProperty(v4->id_toString(), method_toString, 1); + v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d(); } ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, int typeId) @@ -180,7 +179,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj initProto(engine); Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->alloc<QQmlValueTypeReference>(engine)); - ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); + ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); r->setPrototype(proto); r->d()->object = object; r->d()->property = property; r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); @@ -195,7 +194,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria initProto(engine); Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->alloc<QQmlValueTypeWrapper>(engine)); - ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); + ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); r->setPrototype(proto); r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); @@ -292,7 +291,7 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) { - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>(); @@ -327,14 +326,14 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) return Encode(ctx->engine()->newString(result)); } -ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); - QQmlValueTypeWrapper *r = static_cast<QQmlValueTypeWrapper *>(m); + const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); QV4::ExecutionEngine *v4 = r->engine(); // Note: readReferenceValue() can change the reference->type. - if (QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { + if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { if (!reference->readReferenceValue()) return Primitive::undefinedValue().asReturnedValue(); } @@ -410,45 +409,41 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaProperty property = metaObject->property(pd->coreIndex); Q_ASSERT(property.isValid()); - QQmlBinding *newBinding = 0; - - QV4::ScopedFunctionObject f(scope, value); - if (reference && f) { - if (!f->isBinding()) { - // assigning a JS function to a non-var-property is not allowed. - QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); - ScopedString e(scope, v4->newString(error)); - v4->throwError(e); - return; - } + if (reference) { + QV4::ScopedFunctionObject f(scope, value); + if (f) { + if (!f->isBinding()) { + // assigning a JS function to a non-var-property is not allowed. + QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); + ScopedString e(scope, v4->newString(error)); + v4->throwError(e); + return; + } - QQmlContextData *context = QmlContextWrapper::callingContext(v4); + QQmlContextData *context = v4->callingQmlContext(); - QQmlPropertyData cacheData; - cacheData.setFlags(QQmlPropertyData::IsWritable | - QQmlPropertyData::IsValueTypeVirtual); - cacheData.propType = writeBackPropertyType; - cacheData.coreIndex = reference->d()->property; - cacheData.valueTypeFlags = 0; - cacheData.valueTypeCoreIndex = pd->coreIndex; - cacheData.valueTypePropType = property.userType(); + QQmlPropertyData cacheData; + cacheData.setFlags(QQmlPropertyData::IsWritable | + QQmlPropertyData::IsValueTypeVirtual); + cacheData.propType = writeBackPropertyType; + cacheData.coreIndex = reference->d()->property; + cacheData.valueTypeFlags = 0; + cacheData.valueTypeCoreIndex = pd->coreIndex; + cacheData.valueTypePropType = property.userType(); - QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - bindingFunction->initBindingLocation(); + QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); + bindingFunction->initBindingLocation(); - newBinding = new QQmlBinding(value, reference->d()->object, context); - newBinding->setTarget(reference->d()->object, cacheData, context); - } + QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context); + newBinding->setTarget(reference->d()->object, cacheData); + QQmlPropertyPrivate::setBinding(newBinding); + return; + } else { + QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyData::encodeValueTypePropertyIndex(reference->d()->property, pd->coreIndex)); - if (reference) { - QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(reference->d()->object, reference->d()->property, pd->coreIndex, newBinding); - if (oldBinding) - oldBinding->destroy(); + } } - if (newBinding) - return; QVariant v = v4->toVariant(value, property.userType()); diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index cad48e661c..5f0edfb71d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -89,7 +89,7 @@ public: int typeId() const; bool write(QObject *target, int propertyIndex) const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 5b1be15869..cae4bfa196 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -500,8 +500,8 @@ void QQmlVMEVariant::ensureValueType(int t) } QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint() + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint) { - setCallback(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint); } void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) @@ -874,10 +874,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) int flags = *reinterpret_cast<int*>(a[3]); if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) { QQmlData *targetData = QQmlData::get(target); - if (targetData && targetData->hasBindingBit(d->propertyIndex())) { - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0); - if (binding) binding->destroy(); - } + if (targetData && targetData->hasBindingBit(d->propertyIndex())) + QQmlPropertyPrivate::removeBinding(target, d->propertyIdx); } } @@ -1183,7 +1181,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) v8methods = new QV4::PersistentValue[metaData->methodCount]; int methodIndex = index - methodOffset() - plainSignals; - v8methods[methodIndex].set(function.asObject()->engine(), function); + v8methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) @@ -1220,8 +1218,9 @@ bool QQmlVMEMetaObject::ensureVarPropertiesAllocated() void QQmlVMEMetaObject::ensureQObjectWrapper() { - QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); - QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine(); + Q_ASSERT(ctxt && ctxt->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine); + QV4::ExecutionEngine *v4 = ep->v4engine(); QV4::QObjectWrapper::wrap(v4, object); } @@ -1251,7 +1250,7 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) void QQmlVMEMetaObject::allocateVarPropertiesArray() { QQmlEngine *qml = qmlEngine(object); - assert(qml); + Q_ASSERT(qml); QV4::ExecutionEngine *v4 = QV8Engine::getV4(qml->handle()); QV4::Scope scope(v4); varProperties.set(scope.engine, v4->newArrayObject(metaData->varPropertyCount)); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index d0e2e34ff1..44809a26f0 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -63,7 +63,7 @@ #include <private/qv8engine_p.h> #include <private/qflagpointer_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 2a3ede6a22..59927fdac7 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -60,6 +60,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4arraybuffer_p.h> +#include <private/qv4jsonobject_p.h> using namespace QV4; @@ -99,7 +100,7 @@ static ReturnedValue constructMeObject(const Value &thisObj, ExecutionEngine *v4 Scope scope(v4); ScopedObject meObj(scope, v4->newObject()); meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))), thisObj); - ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->v8Engine->callingContext(), 0)); + ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->callingQmlContext(), 0)); meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))), v); return meObj.asReturnedValue(); } @@ -222,8 +223,8 @@ public: static ReturnedValue create(ExecutionEngine *, NodeImpl *, const QList<NodeImpl *> &); // JS API - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; Heap::NamedNodeMap::NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list) @@ -244,8 +245,8 @@ public: V4_NEEDS_DESTROY // JS API - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); // C++ API static ReturnedValue create(ExecutionEngine *, NodeImpl *); @@ -871,10 +872,10 @@ bool Node::isNull() const return d()->d == 0; } -ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue NamedNodeMap::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<NamedNodeMap>()); - NamedNodeMap *r = static_cast<NamedNodeMap *>(m); + const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); if ((int)index < r->d()->list.count()) { @@ -887,14 +888,14 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty return Encode::undefined(); } -ReturnedValue NamedNodeMap::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<NamedNodeMap>()); - NamedNodeMap *r = static_cast<NamedNodeMap *>(m); + const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); name->makeIdentifier(v4); - if (name->equals(v4->id_length)) + if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->list.count()).asReturnedValue(); QString str = name->toQString(); @@ -916,10 +917,10 @@ ReturnedValue NamedNodeMap::create(ExecutionEngine *v4, NodeImpl *data, const QL return (v4->memoryManager->alloc<NamedNodeMap>(v4, data, list))->asReturnedValue(); } -ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue NodeList::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<NodeList>()); - NodeList *r = static_cast<NodeList *>(m); + const NodeList *r = static_cast<const NodeList *>(m); QV4::ExecutionEngine *v4 = r->engine(); if ((int)index < r->d()->d->children.count()) { @@ -932,15 +933,15 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) return Encode::undefined(); } -ReturnedValue NodeList::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<NodeList>()); - NodeList *r = static_cast<NodeList *>(m); + const NodeList *r = static_cast<const NodeList *>(m); QV4::ExecutionEngine *v4 = r->engine(); name->makeIdentifier(v4); - if (name->equals(v4->id_length)) + if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue(); return Object::get(m, name, hasProperty); } @@ -1026,6 +1027,8 @@ public: const QString & responseType() const; void setResponseType(const QString &); + + QV4::ReturnedValue jsonResponseBody(QV4::ExecutionEngine*); private slots: void readyRead(); void error(QNetworkReply::NetworkError); @@ -1076,6 +1079,7 @@ private: QNetworkAccessManager *networkAccessManager() { return m_nam; } QString m_responseType; + QV4::PersistentValue m_parsedJson; }; QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessManager *manager) @@ -1083,6 +1087,7 @@ QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessMa , m_state(Unsent), m_errorFlag(false), m_sendFlag(false) , m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) , m_responseType() + , m_parsedJson() { } @@ -1478,6 +1483,24 @@ void QQmlXMLHttpRequest::setResponseType(const QString &responseType) m_responseType = responseType; } +QV4::ReturnedValue QQmlXMLHttpRequest::jsonResponseBody(QV4::ExecutionEngine* engine) +{ + if (m_parsedJson.isEmpty()) { + Scope scope(engine); + + QJsonParseError error; + const QString& jtext = responseBody(); + JsonParser parser(scope.engine, jtext.constData(), jtext.length()); + ScopedValue jsonObject(scope, parser.parse(&error)); + if (error.error != QJsonParseError::NoError) + return engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); + + m_parsedJson.set(scope.engine, jsonObject); + } + + return m_parsedJson.value(); +} + #ifndef QT_NO_TEXTCODEC QTextCodec* QQmlXMLHttpRequest::findTextCodec() const @@ -1599,7 +1622,7 @@ struct QQmlXMLHttpRequestWrapper : Object { struct QQmlXMLHttpRequestCtor : FunctionObject { QQmlXMLHttpRequestCtor(ExecutionEngine *engine); - Object *proto; + Pointer<Object> proto; }; } @@ -1625,9 +1648,9 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject c->proto->mark(e); FunctionObject::markObjects(that, e); } - static ReturnedValue construct(Managed *that, QV4::CallData *) + static ReturnedValue construct(const Managed *that, QV4::CallData *) { - Scope scope(static_cast<QQmlXMLHttpRequestCtor *>(that)->engine()); + Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); if (!ctor) return scope.engine->throwTypeError(); @@ -1639,7 +1662,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject return w.asReturnedValue(); } - static ReturnedValue call(Managed *, QV4::CallData *) { + static ReturnedValue call(const Managed *, QV4::CallData *) { return Primitive::undefinedValue().asReturnedValue(); } @@ -1679,7 +1702,7 @@ Heap::QQmlXMLHttpRequestCtor::QQmlXMLHttpRequestCtor(ExecutionEngine *engine) ctor->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); if (!ctor->d()->proto) ctor->setupProto(); - ScopedString s(scope, engine->id_prototype); + ScopedString s(scope, engine->id_prototype()); ctor->defineDefaultProperty(s, ScopedObject(scope, ctor->d()->proto)); } @@ -1746,7 +1769,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) QUrl url = QUrl(ctx->args()[1].toQStringNoThrow()); if (url.isRelative()) - url = scope.engine->v8Engine->callingContext()->resolvedUrl(url); + url = scope.engine->callingQmlContext()->resolvedUrl(url); bool async = true; // Argument 2 - async (optional) @@ -1986,6 +2009,8 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(CallContext *ctx) return QV4::Encode(scope.engine->newString(r->responseBody())); } else if (responseType.compare(QLatin1String("arraybuffer"), Qt::CaseInsensitive) == 0) { return QV4::Encode(scope.engine->newArrayBuffer(r->rawResponseBody())); + } else if (responseType.compare(QLatin1String("json"), Qt::CaseInsensitive) == 0) { + return r->jsonResponseBody(scope.engine); } else { return QV4::Encode(scope.engine->newString(QString())); } @@ -2033,7 +2058,7 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->alloc<QQmlXMLHttpRequestCtor>(v4)); ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest"))); - v4->globalObject()->defineReadonlyProperty(s, ctor); + v4->globalObject->defineReadonlyProperty(s, ctor); QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData; return data; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index f53b9a0c7d..aff6de7f5e 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -51,6 +51,7 @@ #include <private/qv4include_p.h> #include <private/qv4context_p.h> #include <private/qv4stringobject_p.h> +#include <private/qv4dateobject_p.h> #include <private/qv4mm_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4objectproto_p.h> @@ -669,7 +670,7 @@ ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx) QVariant argVariant = ctx->engine()->toVariant(ctx->args()[0], -1); QTime time; - if (ctx->args()[0].asDateObject() || (argVariant.type() == QVariant::String)) + if (ctx->args()[0].as<DateObject>() || (argVariant.type() == QVariant::String)) time = argVariant.toDateTime().time(); else // if (argVariant.type() == QVariant::Time), or invalid. time = argVariant.toTime(); @@ -839,21 +840,21 @@ ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx) */ ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx) { - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + ExecutionEngine *v4 = ctx->engine(); - QUrl url = ctx->engine()->toVariant(ctx->args()[0], -1).toUrl(); - QQmlEngine *e = v8engine->engine(); + QUrl url = v4->toVariant(ctx->args()[0], -1).toUrl(); + QQmlEngine *e = v4->qmlEngine(); QQmlEnginePrivate *p = 0; if (e) p = QQmlEnginePrivate::get(e); if (p) { - QQmlContextData *ctxt = v8engine->callingContext(); + QQmlContextData *ctxt = v4->callingQmlContext(); if (ctxt) - return ctx->d()->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); + return v4->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); else - return ctx->d()->engine->newString(url.toString())->asReturnedValue(); + return v4->newString(url.toString())->asReturnedValue(); } - return ctx->d()->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); + return v4->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); } /*! @@ -983,7 +984,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); - QQmlContextData *context = v8engine->callingContext(); + QQmlContextData *context = scope.engine->callingQmlContext(); Q_ASSERT(context); QQmlContext *effectiveContext = 0; if (context->isPragmaLibraryContext) @@ -1090,7 +1091,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); - QQmlContextData *context = v8engine->callingContext(); + QQmlContextData *context = scope.engine->callingQmlContext(); Q_ASSERT(context); QQmlContextData *effectiveContext = context; if (context->isPragmaLibraryContext) @@ -1178,7 +1179,7 @@ ReturnedValue QtObject::method_locale(CallContext *ctx) return QQmlLocale::locale(ctx->engine(), code); } -Heap::QQmlBindingFunction::QQmlBindingFunction(QV4::FunctionObject *originalFunction) +Heap::QQmlBindingFunction::QQmlBindingFunction(const QV4::FunctionObject *originalFunction) : QV4::Heap::FunctionObject(originalFunction->scope(), originalFunction->name()) , originalFunction(originalFunction->d()) { @@ -1191,10 +1192,10 @@ void QQmlBindingFunction::initBindingLocation() d()->bindingLocation.line = frame.line; } -ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData) +ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData) { - Scope scope(static_cast<QQmlBindingFunction*>(that)->engine()); - ScopedFunctionObject function(scope, static_cast<QQmlBindingFunction*>(that)->d()->originalFunction); + Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine()); + ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction); return function->call(callData); } @@ -1256,7 +1257,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) { if (ctx->argc() != 1) V4THROW_ERROR("binding() requires 1 argument"); - QV4::FunctionObject *f = ctx->args()[0].asFunctionObject(); + const QV4::FunctionObject *f = ctx->args()[0].as<FunctionObject>(); if (!f) V4THROW_TYPE("binding(): argument (binding expression) must be a function"); @@ -1267,7 +1268,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) ReturnedValue QtObject::method_get_platform(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); @@ -1284,7 +1285,7 @@ ReturnedValue QtObject::method_get_platform(CallContext *ctx) ReturnedValue QtObject::method_get_application(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); @@ -1379,7 +1380,7 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c if (i != 0) result.append(QLatin1Char(' ')); - if (ctx->args()[i].asArrayObject()) + if (ctx->args()[i].as<ArrayObject>()) result.append(QStringLiteral("[") + ctx->args()[i].toQStringNoThrow() + QStringLiteral("]")); else result.append(ctx->args()[i].toQStringNoThrow()); @@ -1612,7 +1613,7 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject) globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); // string prototype extension - v4->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("arg"), method_string_arg); + v4->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), method_string_arg); } @@ -1726,9 +1727,8 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) V4THROW_ERROR("qsTr(): third argument (n) must be a number"); Scope scope(ctx); - QV8Engine *v8engine = ctx->d()->engine->v8Engine; QString context; - if (QQmlContextData *ctxt = v8engine->callingContext()) { + if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) { QString path = ctxt->urlString(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); int lastDot = path.lastIndexOf(QLatin1Char('.')); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index b78375118b..bdd53fe601 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -68,8 +68,8 @@ struct ConsoleObject : Object { }; struct QQmlBindingFunction : FunctionObject { - QQmlBindingFunction(QV4::FunctionObject *originalFunction); - FunctionObject *originalFunction; + QQmlBindingFunction(const QV4::FunctionObject *originalFunction); + Pointer<FunctionObject> originalFunction; // Set when the binding is created later QQmlSourceLocation bindingLocation; }; @@ -166,7 +166,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject void initBindingLocation(); // from caller stack trace - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/qml/v8/qv4domerrors.cpp b/src/qml/qml/v8/qv4domerrors.cpp index c318e2e550..1baaa113aa 100644 --- a/src/qml/qml/v8/qv4domerrors.cpp +++ b/src/qml/qml/v8/qv4domerrors.cpp @@ -59,7 +59,7 @@ void qt_add_domexceptions(ExecutionEngine *e) domexception->defineReadonlyProperty(QStringLiteral("INVALID_ACCESS_ERR"), Primitive::fromInt32(DOMEXCEPTION_INVALID_ACCESS_ERR)); domexception->defineReadonlyProperty(QStringLiteral("VALIDATION_ERR"), Primitive::fromInt32(DOMEXCEPTION_VALIDATION_ERR)); domexception->defineReadonlyProperty(QStringLiteral("TYPE_MISMATCH_ERR"), Primitive::fromInt32(DOMEXCEPTION_TYPE_MISMATCH_ERR)); - e->globalObject()->defineDefaultProperty(QStringLiteral("DOMException"), domexception); + e->globalObject->defineDefaultProperty(QStringLiteral("DOMException"), domexception); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv4sqlerrors.cpp b/src/qml/qml/v8/qv4sqlerrors.cpp index b7a5b71540..c61e57560d 100644 --- a/src/qml/qml/v8/qv4sqlerrors.cpp +++ b/src/qml/qml/v8/qv4sqlerrors.cpp @@ -51,7 +51,7 @@ void qt_add_sqlexceptions(QV4::ExecutionEngine *engine) sqlexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Primitive::fromInt32(SQLEXCEPTION_SYNTAX_ERR)); sqlexception->defineReadonlyProperty(QStringLiteral("CONSTRAINT_ERR"), Primitive::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR)); sqlexception->defineReadonlyProperty(QStringLiteral("TIMEOUT_ERR"), Primitive::fromInt32(SQLEXCEPTION_TIMEOUT_ERR)); - engine->globalObject()->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception); + engine->globalObject->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index a7c63c9df1..6cb316ce9f 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -61,7 +61,7 @@ #include <QtCore/qdatastream.h> #include <private/qsimd_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4objectiterator_p.h> #include <private/qv4mm_p.h> @@ -171,15 +171,10 @@ const QSet<QString> &QV8Engine::illegalNames() const return m_illegalNames; } -QQmlContextData *QV8Engine::callingContext() -{ - return QV4::QmlContextWrapper::callingContext(m_v4Engine); -} - void QV8Engine::initializeGlobal() { QV4::Scope scope(m_v4Engine); - QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject()); + QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject); QQmlLocale::registerStringLocaleCompare(m_v4Engine); QQmlDateExtension::registerExtension(m_v4Engine); @@ -191,9 +186,9 @@ void QV8Engine::initializeGlobal() qt_add_sqlexceptions(m_v4Engine); { - for (uint i = 0; i < m_v4Engine->globalObject()->internalClass()->size; ++i) { - if (m_v4Engine->globalObject()->internalClass()->nameMap.at(i)) - m_illegalNames.insert(m_v4Engine->globalObject()->internalClass()->nameMap.at(i)->string); + for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) { + if (m_v4Engine->globalObject->internalClass()->nameMap.at(i)) + m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->string); } } @@ -229,7 +224,7 @@ void QV8Engine::freezeObject(const QV4::Value &value) QV4::ScopedFunctionObject f(scope, m_freezeObject.value()); QV4::ScopedCallData callData(scope, 1); callData->args[0] = value; - callData->thisObject = m_v4Engine->globalObject(); + callData->thisObject = m_v4Engine->globalObject; f->call(callData); } @@ -266,9 +261,7 @@ void QV8Engine::setExtensionData(int index, Deletable *data) void QV8Engine::initQmlGlobalObject() { initializeGlobal(); - QV4::Scope scope(m_v4Engine); - QV4::ScopedValue v(scope, m_v4Engine->globalObject()); - freezeObject(v); + freezeObject(*m_v4Engine->globalObject); } void QV8Engine::setEngine(QQmlEngine *engine) @@ -279,7 +272,7 @@ void QV8Engine::setEngine(QQmlEngine *engine) QV4::ReturnedValue QV8Engine::global() { - return m_v4Engine->globalObject()->asReturnedValue(); + return m_v4Engine->globalObject->asReturnedValue(); } void QV8Engine::startTimer(const QString &timerName) diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index fb538772d1..55e4b15b77 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -60,7 +60,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qv4qobjectwrapper_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qv4identifier_p.h> @@ -101,19 +101,19 @@ namespace QV4 { return rv; \ } \ -// Used to allow a QObject method take and return raw V8 handles without having to expose -// v8 in the public API. +// Used to allow a QObject method take and return raw V4 handles without having to expose +// 48 in the public API. // Use like this: // class MyClass : public QObject { // Q_OBJECT // ... -// Q_INVOKABLE void myMethod(QQmlV8Function*); +// Q_INVOKABLE void myMethod(QQmlV4Function*); // }; // The QQmlV8Function - and consequently the arguments and return value - only remains // valid during the call. If the return value isn't set within myMethod(), the will return // undefined. class QV8Engine; -// ### GC + class QQmlV4Function { public: @@ -163,8 +163,6 @@ class QQmlContextData; class Q_QML_PRIVATE_EXPORT QV8Engine { friend class QJSEngine; - // ### GC - typedef QSet<QV4::Heap::Object *> V8ObjectSet; public: static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); } // static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; } @@ -192,8 +190,6 @@ public: Deletable *listModelData() { return m_listModelData; } void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; } - QQmlContextData *callingContext(); - void freezeObject(const QV4::Value &value); // Return the network access manager for this engine. By default this returns the network diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 7814fa6d56..8b94769772 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -52,8 +52,8 @@ QT_BEGIN_NAMESPACE class QQmlBindPrivate : public QObjectPrivate { public: - QQmlBindPrivate() : componentComplete(true), obj(0), prevBind(0) {} - ~QQmlBindPrivate() { if (prevBind) prevBind->destroy(); } + QQmlBindPrivate() : componentComplete(true), obj(0) {} + ~QQmlBindPrivate() { } QQmlNullableValue<bool> when; bool componentComplete; @@ -61,7 +61,7 @@ public: QString propName; QQmlNullableValue<QVariant> value; QQmlProperty prop; - QQmlAbstractBinding *prevBind; + QQmlAbstractBinding::Ptr prevBind; }; @@ -277,22 +277,17 @@ void QQmlBind::eval() if (!d->when) { //restore any previous binding if (d->prevBind) { - QQmlAbstractBinding *tmp = d->prevBind; + QQmlAbstractBinding::Ptr p = d->prevBind; d->prevBind = 0; - tmp = QQmlPropertyPrivate::setBinding(d->prop, tmp); - if (tmp) //should this ever be true? - tmp->destroy(); + QQmlPropertyPrivate::setBinding(p.data()); } return; } //save any set binding for restoration - QQmlAbstractBinding *tmp; - tmp = QQmlPropertyPrivate::setBinding(d->prop, 0); - if (tmp && d->prevBind) - tmp->destroy(); - else if (!d->prevBind) - d->prevBind = tmp; + if (!d->prevBind) + d->prevBind = QQmlPropertyPrivate::binding(d->prop); + QQmlPropertyPrivate::removeBinding(d->prop); } d->prop.write(d->value.value); diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 0c81855e49..6a93410ecb 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -165,7 +165,7 @@ void QQmlConnections::setTarget(QObject *obj) foreach (QQmlBoundSignal *s, d->boundsignals) { // It is possible that target is being changed due to one of our signal // handlers -> use deleteLater(). - if (s->isEvaluating()) + if (s->isNotifying()) (new QQmlBoundSignalDeleter(s))->deleteLater(); else delete s; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 201fd4572c..630c7e7e4a 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -44,7 +44,7 @@ #include <private/qqmlincubator_p.h> #include <private/qqmlcompiler_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <qv4objectiterator_p.h> @@ -86,16 +86,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code); } - static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *) + static QV4::ReturnedValue call(const QV4::Managed *that, QV4::CallData *callData) { - return static_cast<DelegateModelGroupFunction *>(m)->engine()->throwTypeError(); - } - - static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData) - { - QV4::ExecutionEngine *v4 = static_cast<DelegateModelGroupFunction *>(that)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const DelegateModelGroupFunction *>(that)->engine(); QV4::Scope scope(v4); - QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<DelegateModelGroupFunction *>(that)); + QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that)); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject); if (!o) return v4->throwTypeError(QStringLiteral("Not a valid VisualData object")); @@ -1637,7 +1632,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const if (!object.isObject()) return false; - QV4::ExecutionEngine *v4 = object.asObject()->engine(); + QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::ScopedObject o(scope, object); if (!o) @@ -2511,7 +2506,7 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *ind if (!value.isObject()) return false; - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<QV4::Object>()->engine(); QV4::Scope scope(v4); QV4::Scoped<QQmlDelegateModelItemObject> object(scope, value); @@ -2579,9 +2574,9 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args) groups |= model->m_cacheMetaType->parseGroups(val); } - if (v->asArrayObject()) { + if (v->as<QV4::ArrayObject>()) { return; - } else if (v->asObject()) { + } else if (v->as<QV4::Object>()) { model->insert(before, v, groups); model->emitChanges(); } @@ -2626,7 +2621,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args) if (i < args->length() && index >= 0 && index <= model->m_compositor.count(group)) { v = (*args)[i]; - if (v->asObject()) { + if (v->as<QV4::Object>()) { int groups = 1 << d->group; if (++i < args->length()) { QV4::ScopedValue val(scope, (*args)[i]); @@ -3286,12 +3281,12 @@ public: quint32 count() const { return d()->changes.count(); } const QQmlChangeSet::Change &at(int index) const { return d()->changes.at(index); } - static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty) + static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>()); - QV4::ExecutionEngine *v4 = static_cast<QQmlDelegateModelGroupChangeArray *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QQmlDelegateModelGroupChangeArray *>(m)->engine(); QV4::Scope scope(v4); - QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, static_cast<QQmlDelegateModelGroupChangeArray *>(m)); + QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, static_cast<const QQmlDelegateModelGroupChangeArray *>(m)); if (index >= array->count()) { if (hasProperty) @@ -3311,12 +3306,12 @@ public: return object.asReturnedValue(); } - static QV4::ReturnedValue get(QV4::Managed *m, QV4::String *name, bool *hasProperty) + static QV4::ReturnedValue get(const QV4::Managed *m, QV4::String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>()); - QQmlDelegateModelGroupChangeArray *array = static_cast<QQmlDelegateModelGroupChangeArray *>(m); + const QQmlDelegateModelGroupChangeArray *array = static_cast<const QQmlDelegateModelGroupChangeArray *>(m); - if (name->equals(array->engine()->id_length)) { + if (name->equals(array->engine()->id_length())) { if (hasProperty) *hasProperty = true; return QV4::Encode(array->count()); diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index ed97690adb..6fc0e4a9d8 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -150,7 +150,9 @@ const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::R ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0) { - for (int i=0 ; i < other->roles.count() ; ++i) { + const int otherRolesCount = other->roles.count(); + roles.reserve(otherRolesCount); + for (int i=0 ; i < otherRolesCount; ++i) { Role *role = new Role(other->roles[i]); roles.append(role); roleHash.insert(role->name, role); @@ -421,13 +423,13 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) int roleIndex = -1; // Add the value now - if (QV4::String *s = propertyValue->asString()) { + if (const QV4::String *s = propertyValue->as<QV4::String>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); roleIndex = e->setStringProperty(r, s->toQString()); } else if (propertyValue->isNumber()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); roleIndex = e->setDoubleProperty(r, propertyValue->asDouble()); - } else if (QV4::ArrayObject *a = propertyValue->asArrayObject()) { + } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); ListModel *subModel = new ListModel(r.subLayout, 0, -1); @@ -441,11 +443,11 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) } else if (propertyValue->isBoolean()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); roleIndex = e->setBoolProperty(r, propertyValue->booleanValue()); - } else if (QV4::DateObject *dd = propertyValue->asDateObject()) { + } else if (QV4::DateObject *dd = propertyValue->as<QV4::DateObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); QDateTime dt = dd->toQDateTime(); roleIndex = e->setDateTimeProperty(r, dt); - } else if (QV4::Object *o = propertyValue->asObject()) { + } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) { if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { QObject *o = wrapper->object(); const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); @@ -502,7 +504,7 @@ void ListModel::set(int elementIndex, QV4::Object *object) if (r.type == ListLayout::Role::Number) { e->setDoublePropertyFast(r, propertyValue->asDouble()); } - } else if (QV4::ArrayObject *a = propertyValue->asArrayObject()) { + } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); if (r.type == ListLayout::Role::List) { ListModel *subModel = new ListModel(r.subLayout, 0, -1); @@ -520,13 +522,13 @@ void ListModel::set(int elementIndex, QV4::Object *object) if (r.type == ListLayout::Role::Bool) { e->setBoolPropertyFast(r, propertyValue->booleanValue()); } - } else if (QV4::DateObject *date = propertyValue->asDateObject()) { + } else if (QV4::DateObject *date = propertyValue->as<QV4::DateObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); if (r.type == ListLayout::Role::DateTime) { QDateTime dt = date->toQDateTime();; e->setDateTimePropertyFast(r, dt); } - } else if (QV4::Object *o = propertyValue->asObject()) { + } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) { if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { QObject *o = wrapper->object(); const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); @@ -1169,7 +1171,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d roleIndex = setStringProperty(role, qstr); } else if (d.isNumber()) { roleIndex = setDoubleProperty(role, d.asDouble()); - } else if (d.asArrayObject()) { + } else if (d.as<QV4::ArrayObject>()) { QV4::ScopedArrayObject a(scope, d); if (role.type == ListLayout::Role::List) { QV4::Scope scope(a->engine()); @@ -1187,7 +1189,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d } } else if (d.isBoolean()) { roleIndex = setBoolProperty(role, d.booleanValue()); - } else if (d.asDateObject()) { + } else if (d.as<QV4::DateObject>()) { QV4::Scoped<QV4::DateObject> dd(scope, d); QDateTime dt = dd->toQDateTime(); roleIndex = setDateTimeProperty(role, dt); @@ -1330,8 +1332,8 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int> QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner); QVariantList subArray = value.toList(); - QVariantList::const_iterator subIt = subArray.begin(); - QVariantList::const_iterator subEnd = subArray.end(); + QVariantList::const_iterator subIt = subArray.cbegin(); + QVariantList::const_iterator subEnd = subArray.cend(); while (subIt != subEnd) { const QVariantMap &subObject = subIt->toMap(); subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel)); @@ -1398,8 +1400,8 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index) QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel); QVariantList subArray = v.toList(); - QVariantList::const_iterator subIt = subArray.begin(); - QVariantList::const_iterator subEnd = subArray.end(); + QVariantList::const_iterator subIt = subArray.cbegin(); + QVariantList::const_iterator subEnd = subArray.cend(); while (subIt != subEnd) { const QVariantMap &subObject = subIt->toMap(); subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel)); diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp index 3e53efd8b9..062d30c252 100644 --- a/src/qml/types/qqmlmodelsmodule.cpp +++ b/src/qml/types/qqmlmodelsmodule.cpp @@ -48,6 +48,7 @@ void QQmlModelsModule::defineModule() qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel"); qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup"); qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel"); + qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel"); qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel"); } diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 1d892beabf..0076c26950 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -36,10 +36,12 @@ #include <QtCore/qcoreapplication.h> #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlengine.h> +#include <QtQml/qqmlinfo.h> #include <private/qqmlchangeset_p.h> #include <private/qqmlglobal_p.h> #include <private/qobject_p.h> +#include <private/qpodvector_p.h> #include <QtCore/qhash.h> #include <QtCore/qlist.h> @@ -67,9 +69,8 @@ public: QQmlObjectModelPrivate() : QObjectPrivate() {} static void children_append(QQmlListProperty<QObject> *prop, QObject *item) { - static_cast<QQmlObjectModelPrivate *>(prop->data)->children.append(Item(item)); - static_cast<QQmlObjectModelPrivate *>(prop->data)->itemAppended(); - static_cast<QQmlObjectModelPrivate *>(prop->data)->emitChildrenChanged(); + int index = static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count(); + static_cast<QQmlObjectModelPrivate *>(prop->data)->insert(index, item); } static int children_count(QQmlListProperty<QObject> *prop) { @@ -81,33 +82,77 @@ public: } static void children_clear(QQmlListProperty<QObject> *prop) { - static_cast<QQmlObjectModelPrivate *>(prop->data)->itemCleared(static_cast<QQmlObjectModelPrivate *>(prop->data)->children); - static_cast<QQmlObjectModelPrivate *>(prop->data)->children.clear(); - static_cast<QQmlObjectModelPrivate *>(prop->data)->emitChildrenChanged(); + static_cast<QQmlObjectModelPrivate *>(prop->data)->clear(); } - void itemAppended() { + void insert(int index, QObject *item) { Q_Q(QQmlObjectModel); - QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.last().item); - attached->setIndex(children.count()-1); + children.insert(index, Item(item)); + for (int i = index; i < children.count(); ++i) { + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + attached->setIndex(i); + } QQmlChangeSet changeSet; - changeSet.insert(children.count() - 1, 1); + changeSet.insert(index, 1); emit q->modelUpdated(changeSet, false); emit q->countChanged(); + emit q->childrenChanged(); } - void itemCleared(const QList<Item> &children) { + void move(int from, int to, int n) { Q_Q(QQmlObjectModel); - foreach (const Item &child, children) - emit q->destroyingItem(child.item); - emit q->countChanged(); + if (from > to) { + // Only move forwards - flip if backwards moving + int tfrom = from; + int tto = to; + from = tto; + to = tto+n; + n = tfrom-tto; + } + + QPODVector<QQmlObjectModelPrivate::Item, 4> store; + for (int i = 0; i < to - from; ++i) + store.append(children[from + n + i]); + for (int i = 0; i < n; ++i) + store.append(children[from + i]); + + for (int i = 0; i < store.count(); ++i) { + children[from + i] = store[i]; + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(from + i).item); + attached->setIndex(from + i); + } + + QQmlChangeSet changeSet; + changeSet.move(from, to, n, -1); + emit q->modelUpdated(changeSet, false); + emit q->childrenChanged(); } - void emitChildrenChanged() { + void remove(int index, int n) { Q_Q(QQmlObjectModel); + for (int i = index; i < index + n; ++i) { + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + attached->setIndex(-1); + } + children.erase(children.begin() + index, children.begin() + index + n); + for (int i = index; i < children.count(); ++i) { + QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + attached->setIndex(i); + } + QQmlChangeSet changeSet; + changeSet.remove(index, n); + emit q->modelUpdated(changeSet, false); + emit q->countChanged(); emit q->childrenChanged(); } + void clear() { + Q_Q(QQmlObjectModel); + foreach (const Item &child, children) + emit q->destroyingItem(child.item); + remove(0, children.count()); + } + int indexOf(QObject *item) const { for (int i = 0; i < children.count(); ++i) if (children.at(i).item == item) @@ -258,4 +303,133 @@ QQmlObjectModelAttached *QQmlObjectModel::qmlAttachedProperties(QObject *obj) return QQmlObjectModelAttached::properties(obj); } +/*! + \qmlmethod object QtQml.Models::ObjectModel::get(int index) + \since 5.6 + + Returns the item at \a index in the model. This allows the item + to be accessed or modified from JavaScript: + + \code + Component.onCompleted: { + objectModel.append(objectComponent.createObject()) + console.log(objectModel.get(0).objectName); + objectModel.get(0).objectName = "first"; + } + \endcode + + The \a index must be an element in the list. + + \sa append() +*/ +QObject *QQmlObjectModel::get(int index) const +{ + Q_D(const QQmlObjectModel); + if (index < 0 || index >= d->children.count()) + return 0; + return d->children.at(index).item; +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::append(object item) + \since 5.6 + + Appends a new item to the end of the model. + + \code + objectModel.append(objectComponent.createObject()) + \endcode + + \sa insert(), remove() +*/ +void QQmlObjectModel::append(QObject *object) +{ + Q_D(QQmlObjectModel); + d->insert(count(), object); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::insert(int index, object item) + \since 5.6 + + Inserts a new item to the model at position \a index. + + \code + objectModel.insert(2, objectComponent.createObject()) + \endcode + + The \a index must be to an existing item in the list, or one past + the end of the list (equivalent to append). + + \sa append(), remove() +*/ +void QQmlObjectModel::insert(int index, QObject *object) +{ + Q_D(QQmlObjectModel); + if (index < 0 || index > count()) { + qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + return; + } + d->insert(index, object); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::move(int from, int to, int n = 1) + \since 5.6 + + Moves \a n items \a from one position \a to another. + + The from and to ranges must exist; for example, to move the first 3 items + to the end of the model: + + \code + objectModel.move(0, objectModel.count - 3, 3) + \endcode + + \sa append() +*/ +void QQmlObjectModel::move(int from, int to, int n) +{ + Q_D(QQmlObjectModel); + if (n <= 0 || from == to) + return; + if (from < 0 || to < 0 || from + n > count() || to + n > count()) { + qmlInfo(this) << tr("move: out of range"); + return; + } + d->move(from, to, n); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::remove(int index, int n = 1) + \since 5.6 + + Removes the items at \a index from the model. + + \sa clear() +*/ +void QQmlObjectModel::remove(int index, int n) +{ + Q_D(QQmlObjectModel); + if (index < 0 || n <= 0 || index + n > count()) { + qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count()); + return; + } + d->remove(index, n); +} + +/*! + \qmlmethod QtQml.Models::ObjectModel::clear() + \since 5.6 + + Clears all items from the model. + + \sa append(), remove() +*/ +void QQmlObjectModel::clear() +{ + Q_D(QQmlObjectModel); + d->clear(); +} + QT_END_NAMESPACE diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h index 4c37a5ac30..9f56ad7121 100644 --- a/src/qml/types/qqmlobjectmodel_p.h +++ b/src/qml/types/qqmlobjectmodel_p.h @@ -107,6 +107,15 @@ public: static QQmlObjectModelAttached *qmlAttachedProperties(QObject *obj); + Q_REVISION(3) Q_INVOKABLE QObject *get(int index) const; + Q_REVISION(3) Q_INVOKABLE void append(QObject *object); + Q_REVISION(3) Q_INVOKABLE void insert(int index, QObject *object); + Q_REVISION(3) Q_INVOKABLE void move(int from, int to, int n = 1); + Q_REVISION(3) Q_INVOKABLE void remove(int index, int n = 1); + +public Q_SLOTS: + Q_REVISION(3) void clear(); + Q_SIGNALS: void childrenChanged(); @@ -120,7 +129,7 @@ class QQmlObjectModelAttached : public QObject public: QQmlObjectModelAttached(QObject *parent) - : QObject(parent), m_index(0) {} + : QObject(parent), m_index(-1) {} ~QQmlObjectModelAttached() { attachedProperties.remove(parent()); } diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index c2c6e5ef5c..0aa5dc4ef6 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -54,7 +54,7 @@ #include <private/qv8engine_p.h> #include <private/qv4serialize_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4scopedvalue_p.h> diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 356970eef0..17f4ffd62b 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -38,7 +38,7 @@ #include <private/qqmlproperty_p.h> #include <private/qv8engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -159,7 +159,9 @@ public: signalIndexes.append(propertyId + signalOffset); } if (roles.isEmpty()) { - for (int propertyId = 0; propertyId < propertyRoles.count(); ++propertyId) + const int propertyRolesCount = propertyRoles.count(); + signalIndexes.reserve(propertyRolesCount); + for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId) signalIndexes.append(propertyId + signalOffset); } diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro index df1b750282..85f21ce6f6 100644 --- a/src/qmldevtools/qmldevtools.pro +++ b/src/qmldevtools/qmldevtools.pro @@ -19,3 +19,4 @@ include(../3rdparty/masm/masm-defs.pri) include(../qml/parser/parser.pri) include(../qml/jsruntime/jsruntime.pri) include(../qml/compiler/compiler.pri) +include(../qml/memory/memory.pri) diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro index 24b87588b8..289a0584e0 100644 --- a/src/qmltest/qmltest.pro +++ b/src/qmltest/qmltest.pro @@ -1,8 +1,8 @@ TARGET = QtQuickTest DEFINES += QT_NO_URL_CAST_FROM_STRING -QT = core -QT_PRIVATE = testlib-private quick qml-private gui core-private +QT = core testlib-private +QT_PRIVATE = quick qml-private gui core-private # Testlib is only a private dependency, which results in our users not # inheriting testlibs's MODULE_CONFIG transitively. Make it explicit. diff --git a/src/qmltest/quicktest.h b/src/qmltest/quicktest.h index 49bd7edfaa..b317a07db4 100644 --- a/src/qmltest/quicktest.h +++ b/src/qmltest/quicktest.h @@ -35,9 +35,12 @@ #define QUICKTEST_H #include <QtQuickTest/quicktestglobal.h> +#include <QtTest/qtest.h> QT_BEGIN_NAMESPACE +QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS + Q_QUICK_TEST_EXPORT int quick_test_main(int argc, char **argv, const char *name, const char *sourceDir); #ifdef QUICK_TEST_SOURCE_DIR @@ -45,12 +48,16 @@ Q_QUICK_TEST_EXPORT int quick_test_main(int argc, char **argv, const char *name, #define QUICK_TEST_MAIN(name) \ int main(int argc, char **argv) \ { \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + QTEST_SET_MAIN_SOURCE_PATH \ return quick_test_main(argc, argv, #name, QUICK_TEST_SOURCE_DIR); \ } #define QUICK_TEST_OPENGL_MAIN(name) \ int main(int argc, char **argv) \ { \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + QTEST_SET_MAIN_SOURCE_PATH \ return quick_test_main(argc, argv, #name, QUICK_TEST_SOURCE_DIR); \ } @@ -59,12 +66,16 @@ Q_QUICK_TEST_EXPORT int quick_test_main(int argc, char **argv, const char *name, #define QUICK_TEST_MAIN(name) \ int main(int argc, char **argv) \ { \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + QTEST_SET_MAIN_SOURCE_PATH \ return quick_test_main(argc, argv, #name, 0); \ } #define QUICK_TEST_OPENGL_MAIN(name) \ int main(int argc, char **argv) \ { \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + QTEST_SET_MAIN_SOURCE_PATH \ return quick_test_main(argc, argv, #name, 0); \ } diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp index 3f91ce85a8..57ba65e588 100644 --- a/src/qmltest/quicktestresult.cpp +++ b/src/qmltest/quicktestresult.cpp @@ -34,6 +34,7 @@ #include "quicktestresult_p.h" #include <QtTest/qtestcase.h> #include <QtTest/qtestsystem.h> +#include <QtTest/private/qtestblacklist_p.h> #include <QtTest/private/qtestresult_p.h> #include <QtTest/private/qtesttable_p.h> #include <QtTest/private/qtestlog_p.h> @@ -108,6 +109,14 @@ public Q_SLOTS: pixel += x; return QColor::fromRgba(*pixel); } + + bool equals(QuickTestImageObject *other) const + { + if (!other) + return m_image.isNull(); + + return m_image == other->m_image; + } private: QImage m_image; }; @@ -205,6 +214,7 @@ void QuickTestResult::setFunctionName(const QString &name) QString fullName = d->testCaseName + QLatin1String("::") + name; QTestResult::setCurrentTestFunction (d->intern(fullName).constData()); + QTestPrivate::checkBlackLists(fullName.toUtf8().constData(), 0); } } else { QTestResult::setCurrentTestFunction(0); @@ -233,6 +243,7 @@ void QuickTestResult::setDataTag(const QString &tag) if (!tag.isEmpty()) { QTestData *data = &(QTest::newRow(tag.toUtf8().constData())); QTestResult::setCurrentTestData(data); + QTestPrivate::checkBlackLists((testCaseName() + QStringLiteral("::") + functionName()).toUtf8().constData(), tag.toUtf8().constData()); emit dataTagChanged(); } else { QTestResult::setCurrentTestData(0); @@ -270,6 +281,8 @@ bool QuickTestResult::isSkipped() const void QuickTestResult::setSkipped(bool skip) { QTestResult::setSkipCurrentTest(skip); + if (!skip) + QTestResult::setBlacklistCurrentTest(false); emit skippedChanged(); } @@ -478,8 +491,8 @@ void QuickTestResult::stringify(QQmlV4Function *args) //Check for Object Type if (value->isObject() - && !value->asFunctionObject() - && !value->asArrayObject()) { + && !value->as<QV4::FunctionObject>() + && !value->as<QV4::ArrayObject>()) { QVariant v = scope.engine->toVariant(value, QMetaType::UnknownType); if (v.isValid()) { switch (v.type()) { @@ -500,7 +513,7 @@ void QuickTestResult::stringify(QQmlV4Function *args) if (result.isEmpty()) { QString tmp = value->toQStringNoThrow(); - if (value->asArrayObject()) + if (value->as<QV4::ArrayObject>()) result.append(QString::fromLatin1("[%1]").arg(tmp)); else result.append(tmp); @@ -707,6 +720,8 @@ void QuickTestResult::parseArgs(int argc, char *argv[]) void QuickTestResult::setProgramName(const char *name) { if (name) { + QTestPrivate::parseBlackList(); + QTestPrivate::parseGpuBlackList(); QTestResult::reset(); } else if (!name && loggingStarted) { QTestResult::setCurrentTestObject(globalProgramName); diff --git a/src/qmltest/quicktestresult_p.h b/src/qmltest/quicktestresult_p.h index 80f84bfa55..45df83621f 100644 --- a/src/qmltest/quicktestresult_p.h +++ b/src/qmltest/quicktestresult_p.h @@ -50,7 +50,6 @@ class QuickTestResultPrivate; class Q_QUICK_TEST_EXPORT QuickTestResult : public QObject { Q_OBJECT - Q_ENUMS(RunMode) Q_PROPERTY(QString testCaseName READ testCaseName WRITE setTestCaseName NOTIFY testCaseNameChanged) Q_PROPERTY(QString functionName READ functionName WRITE setFunctionName NOTIFY functionNameChanged) Q_PROPERTY(QString dataTag READ dataTag WRITE setDataTag NOTIFY dataTagChanged) @@ -70,6 +69,7 @@ public: RepeatUntilValidMeasurement, RunOnce }; + Q_ENUM(RunMode) QString testCaseName() const; void setTestCaseName(const QString &name); diff --git a/src/quick/designer/designersupport.cpp b/src/quick/designer/designersupport.cpp index 56d2badb62..3f66e81ea7 100644 --- a/src/quick/designer/designersupport.cpp +++ b/src/quick/designer/designersupport.cpp @@ -213,10 +213,7 @@ bool isValidAnchorName(const QString &name) bool DesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem) { -#ifndef QT_NO_DYNAMIC_CAST - Q_ASSERT(dynamic_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(fromItem))); -#endif - QQuickItemPrivate *fromItemPrivate = static_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(fromItem)); + QQuickItemPrivate *fromItemPrivate = QQuickItemPrivate::get(fromItem); QQuickAnchors *anchors = fromItemPrivate->anchors(); return anchors->fill() == toItem || anchors->centerIn() == toItem @@ -246,7 +243,7 @@ bool DesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *to QQuickAnchors *anchors(QQuickItem *item) { - QQuickItemPrivate *itemPrivate = static_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(item)); + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); return itemPrivate->anchors(); } @@ -398,7 +395,7 @@ QList<QObject*> DesignerSupport::statesForItem(QQuickItem *item) bool DesignerSupport::isComponentComplete(QQuickItem *item) { - return static_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(item))->componentComplete; + return QQuickItemPrivate::get(item)->componentComplete; } int DesignerSupport::borderWidth(QQuickItem *item) diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index cb694c499a..8fa290b953 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -46,7 +46,7 @@ #include <QtCore/QBuffer> #include <QtCore/qdatetime.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4scopedvalue_p.h> @@ -990,7 +990,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url) if (!d->pixmaps.contains(fullPathUrl)) { QQuickPixmap* pix = new QQuickPixmap(); QQmlRefPointer<QQuickCanvasPixmap> canvasPix; - canvasPix.take(new QQuickCanvasPixmap(pix)); + canvasPix.adopt(new QQuickCanvasPixmap(pix)); d->pixmaps.insert(fullPathUrl, canvasPix); pix->load(qmlEngine(this) diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h index bcd7072903..4a1a59d61e 100644 --- a/src/quick/items/context2d/qquickcanvasitem_p.h +++ b/src/quick/items/context2d/qquickcanvasitem_p.h @@ -68,8 +68,6 @@ private: class QQuickCanvasItem : public QQuickItem { Q_OBJECT - Q_ENUMS(RenderTarget) - Q_ENUMS(RenderStrategy) Q_PROPERTY(bool available READ isAvailable NOTIFY availableChanged) Q_PROPERTY(QString contextType READ contextType WRITE setContextType NOTIFY contextTypeChanged) @@ -85,12 +83,14 @@ public: Image, FramebufferObject }; + Q_ENUM(RenderTarget) enum RenderStrategy { Immediate, Threaded, Cooperative }; + Q_ENUM(RenderStrategy) QQuickCanvasItem(QQuickItem *parent = 0); ~QQuickCanvasItem(); diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 4aa3b1c8d0..1ebbe3bdac 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -53,7 +53,7 @@ #include <private/qv4object_p.h> #include <private/qquickwindow_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> @@ -884,7 +884,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object V4_OBJECT2(QQuickJSContext2DPixelData, QV4::Object) V4_NEEDS_DESTROY - static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty); + static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty); static void putIndexed(QV4::Managed *m, uint index, const QV4::Value &value); static QV4::ReturnedValue proto_get_length(QV4::CallContext *ctx); @@ -1379,7 +1379,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx QV4::ScopedValue value(scope, ctx->argument(0)); - if (value->asObject()) { + if (value->as<Object>()) { QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>(); if (color.isValid()) { r->d()->context->state.fillStyle = color; @@ -1488,7 +1488,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *c QV4::ScopedValue value(scope, ctx->argument(0)); - if (value->asObject()) { + if (value->as<Object>()) { QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>(); if (color.isValid()) { r->d()->context->state.fillStyle = color; @@ -1719,7 +1719,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon } else { QImage patternTexture; - if (QV4::Object *o = ctx->args()[0].asObject()) { + if (const QV4::Object *o = ctx->args()[0].as<Object>()) { QV4::ScopedString s(scope, scope.engine->newString(QStringLiteral("data"))); QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s)); if (!!pixelData) { @@ -2912,7 +2912,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext } else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) { QImage img = canvas->toImage(); if (!img.isNull()) - pixmap.take(new QQuickCanvasPixmap(img)); + pixmap.adopt(new QQuickCanvasPixmap(img)); } else { V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch"); } @@ -2921,7 +2921,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext if (!!imageData) { QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (pix && !pix->d()->image.isNull()) { - pixmap.take(new QQuickCanvasPixmap(pix->d()->image)); + pixmap.adopt(new QQuickCanvasPixmap(pix->d()->image)); } else { V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch"); } @@ -3089,12 +3089,12 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::CallContext return QV4::Encode(r->d()->image.width() * r->d()->image.height() * 4); } -QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint index, bool *hasProperty) +QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<QQuickJSContext2DPixelData>()); - QV4::ExecutionEngine *v4 = static_cast<QQuickJSContext2DPixelData *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QQuickJSContext2DPixelData *>(m)->engine(); QV4::Scope scope(v4); - QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m)); + QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<const QQuickJSContext2DPixelData *>(m)); if (index < static_cast<quint32>(r->d()->image.width() * r->d()->image.height() * 4)) { if (hasProperty) @@ -3357,7 +3357,7 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo qreal pos = ctx->args()[0].toNumber(); QColor color; - if (ctx->args()[1].asObject()) { + if (ctx->args()[1].as<Object>()) { color = scope.engine->toVariant(ctx->args()[1], qMetaTypeId<QColor>()).value<QColor>(); } else { color = qt_color_from_string(ctx->args()[1]); @@ -4235,7 +4235,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4) gradientProto = proto; proto = scope.engine->newObject(); - proto->defineAccessorProperty(scope.engine->id_length, QQuickJSContext2DPixelData::proto_get_length, 0); + proto->defineAccessorProperty(scope.engine->id_length(), QQuickJSContext2DPixelData::proto_get_length, 0); pixelArrayProto = proto; } diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index 67d3a2e4fb..78fa26d791 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -48,7 +48,7 @@ #include <private/qv8engine_p.h> #include <QtCore/QWaitCondition> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> //#define QQUICKCONTEXT2D_DEBUG //enable this for just DEBUG purpose! diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp index f559f166bf..606d4c45da 100644 --- a/src/quick/items/qquickanchors.cpp +++ b/src/quick/items/qquickanchors.cpp @@ -414,13 +414,27 @@ void QQuickAnchorsPrivate::updateMe() void QQuickAnchorsPrivate::updateOnComplete() { //optimization to only set initial dependencies once, at completion time - QSet<QQuickItem *> dependencies; - dependencies << fill << centerIn - << left.item << right.item << hCenter.item - << top.item << bottom.item << vCenter.item << baseline.item; - - foreach (QQuickItem *dependency, dependencies) - addDepend(dependency); + QQuickItem *dependencies[9]; + dependencies[0] = fill; + dependencies[1] = centerIn; + dependencies[2] = left.item; + dependencies[3] = right.item; + dependencies[4] = hCenter.item; + dependencies[5] = top.item; + dependencies[6] = bottom.item; + dependencies[7] = vCenter.item; + dependencies[8] = baseline.item; + + std::sort(dependencies, dependencies + 9); + + QQuickItem *lastDependency = 0; + for (int i = 0; i < 9; ++i) { + QQuickItem *dependency = dependencies[i]; + if (lastDependency != dependency) { + addDepend(dependency); + lastDependency = dependency; + } + } update(); } diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h index 4778afc88b..a10ebb4b73 100644 --- a/src/quick/items/qquickanimatedsprite_p.h +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -70,12 +70,12 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged) - Q_ENUMS(LoopParameters) public: explicit QQuickAnimatedSprite(QQuickItem *parent = 0); enum LoopParameters { Infinite = -1 }; + Q_ENUM(LoopParameters) bool running() const { diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h index f2a172fad3..8a88e3d0d3 100644 --- a/src/quick/items/qquickborderimage_p.h +++ b/src/quick/items/qquickborderimage_p.h @@ -44,7 +44,6 @@ class QQuickBorderImagePrivate; class Q_AUTOTEST_EXPORT QQuickBorderImage : public QQuickImageBase { Q_OBJECT - Q_ENUMS(TileMode) Q_PROPERTY(QQuickScaleGrid *border READ border CONSTANT) Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged) @@ -59,6 +58,7 @@ public: QQuickScaleGrid *border(); enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile }; + Q_ENUM(TileMode) TileMode horizontalTileMode() const; void setHorizontalTileMode(TileMode); diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index 4bd4cfc6fd..2b4b2a51d4 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -140,7 +140,6 @@ class Q_AUTOTEST_EXPORT QQuickDrag : public QObject { Q_OBJECT - Q_ENUMS(Axis DragType) Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget) Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged) Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged) @@ -160,12 +159,14 @@ public: ~QQuickDrag(); enum DragType { None, Automatic, Internal }; + Q_ENUM(DragType) QQuickItem *target() const; void setTarget(QQuickItem *target); void resetTarget(); enum Axis { XAxis=0x01, YAxis=0x02, XAndYAxis=0x03, XandYAxis=XAndYAxis }; + Q_ENUM(Axis) Axis axis() const; void setAxis(Axis); diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 52142346ab..bfb732554b 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1330,7 +1330,7 @@ void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event) if (window() && window()->mouseGrabberItem()) { QPointF localPos = window()->mouseGrabberItem()->mapFromScene(event->windowPos()); QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos)); - window()->sendEvent(window()->mouseGrabberItem(), mouseEvent.data()); + QCoreApplication::sendEvent(window(), mouseEvent.data()); } // And the event has been consumed @@ -1434,6 +1434,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->lastPosTime = currentTimestamp; d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta()); d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, velocity); + event->accept(); } if (!event->isAccepted()) diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 3c3cd362dd..c974da66d6 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -93,7 +93,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem Q_PROPERTY(QQmlListProperty<QQuickItem> flickableChildren READ flickableChildren) Q_CLASSINFO("DefaultProperty", "flickableData") - Q_ENUMS(FlickableDirection) Q_FLAGS(BoundsBehavior) public: @@ -177,6 +176,7 @@ public: QQuickItem *contentItem(); enum FlickableDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 }; + Q_ENUM(FlickableDirection) FlickableDirection flickableDirection() const; void setFlickableDirection(FlickableDirection); diff --git a/src/quick/items/qquickflipable_p.h b/src/quick/items/qquickflipable_p.h index bd2efe0676..31bfe97923 100644 --- a/src/quick/items/qquickflipable_p.h +++ b/src/quick/items/qquickflipable_p.h @@ -47,7 +47,6 @@ class Q_AUTOTEST_EXPORT QQuickFlipable : public QQuickItem { Q_OBJECT - Q_ENUMS(Side) Q_PROPERTY(QQuickItem *front READ front WRITE setFront NOTIFY frontChanged) Q_PROPERTY(QQuickItem *back READ back WRITE setBack NOTIFY backChanged) Q_PROPERTY(Side side READ side NOTIFY sideChanged) @@ -64,6 +63,7 @@ public: void setBack(QQuickItem *); enum Side { Front, Back }; + Q_ENUM(Side) Side side() const; Q_SIGNALS: diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp index c3e5b97baf..18e786fea4 100644 --- a/src/quick/items/qquickframebufferobject.cpp +++ b/src/quick/items/qquickframebufferobject.cpp @@ -47,11 +47,13 @@ class QQuickFramebufferObjectPrivate : public QQuickItemPrivate public: QQuickFramebufferObjectPrivate() : followsItemSize(true) + , mirrorVertically(false) , node(0) { } bool followsItemSize; + bool mirrorVertically; mutable QSGFramebufferObjectNode *node; }; @@ -138,6 +140,34 @@ bool QQuickFramebufferObject::textureFollowsItemSize() const } /*! + * \property QQuickFramebufferObject::mirrorVertically + * + * This property controls if the size of the FBO's contents should be mirrored + * vertically when drawing. This allows easy integration of third-party + * rendering code that does not follow the standard expectations. + * + * The default value is \c {false}. + * + * \since 5.6 + */ + +void QQuickFramebufferObject::setMirrorVertically(bool enable) +{ + Q_D(QQuickFramebufferObject); + if (d->mirrorVertically == enable) + return; + d->mirrorVertically = enable; + emit mirrorVerticallyChanged(d->mirrorVertically); + update(); +} + +bool QQuickFramebufferObject::mirrorVertically() const +{ + Q_D(const QQuickFramebufferObject); + return d->mirrorVertically; +} + +/*! * \internal */ void QQuickFramebufferObject::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) @@ -290,6 +320,7 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode QQuickWindow::TextureHasAlphaChannel)); } + n->setTextureCoordinatesTransform(d->mirrorVertically ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform); n->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest); n->setRect(0, 0, width(), height()); diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h index 4a0248c082..7fb7262222 100644 --- a/src/quick/items/qquickframebufferobject.h +++ b/src/quick/items/qquickframebufferobject.h @@ -49,6 +49,7 @@ class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem Q_DECLARE_PRIVATE(QQuickFramebufferObject) Q_PROPERTY(bool textureFollowsItemSize READ textureFollowsItemSize WRITE setTextureFollowsItemSize NOTIFY textureFollowsItemSizeChanged) + Q_PROPERTY(bool mirrorVertically READ mirrorVertically WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged) public: @@ -73,6 +74,9 @@ public: bool textureFollowsItemSize() const; void setTextureFollowsItemSize(bool follows); + bool mirrorVertically() const; + void setMirrorVertically(bool enable); + virtual Renderer *createRenderer() const = 0; bool isTextureProvider() const Q_DECL_OVERRIDE; @@ -87,6 +91,7 @@ protected: Q_SIGNALS: void textureFollowsItemSizeChanged(bool); + void mirrorVerticallyChanged(bool); private Q_SLOTS: void invalidateSceneGraph(); diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 3cc0a28b87..e3f216b3a2 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -267,9 +267,13 @@ qreal QQuickGridViewPrivate::originPosition() const qreal QQuickGridViewPrivate::lastPosition() const { qreal pos = 0; - if (model && model->count()) { - // get end position of last item - pos = (rowPosAt(model->count() - 1) + rowSize()); + if (model && (model->count() || !visibleItems.isEmpty())) { + qreal lastRowPos = model->count() ? rowPosAt(model->count() - 1) : 0; + if (!visibleItems.isEmpty()) { + // If there are items in delayRemove state, they may be after any items linked to the model + lastRowPos = qMax(lastRowPos, static_cast<FxGridItemSG*>(visibleItems.last())->rowPos()); + } + pos = lastRowPos + rowSize(); } return pos; } diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h index 7e1ace01dd..389ef27585 100644 --- a/src/quick/items/qquickgridview_p.h +++ b/src/quick/items/qquickgridview_p.h @@ -52,8 +52,6 @@ class Q_AUTOTEST_EXPORT QQuickGridView : public QQuickItemView Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged) - Q_ENUMS(SnapMode) - Q_ENUMS(Flow) Q_CLASSINFO("DefaultProperty", "data") public: @@ -61,6 +59,7 @@ public: FlowLeftToRight = LeftToRight, FlowTopToBottom = TopToBottom }; + Q_ENUM(Flow) QQuickGridView(QQuickItem *parent=0); ~QQuickGridView(); @@ -78,6 +77,7 @@ public: void setCellHeight(qreal); enum SnapMode { NoSnap, SnapToRow, SnapOneRow }; + Q_ENUM(SnapMode) SnapMode snapMode() const; void setSnapMode(SnapMode mode); diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h index 8edf153ca3..a780f9a626 100644 --- a/src/quick/items/qquickimage_p.h +++ b/src/quick/items/qquickimage_p.h @@ -40,12 +40,9 @@ QT_BEGIN_NAMESPACE class QQuickImagePrivate; -class Q_AUTOTEST_EXPORT QQuickImage : public QQuickImageBase +class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase { Q_OBJECT - Q_ENUMS(FillMode) - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedGeometryChanged) @@ -62,11 +59,14 @@ public: enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally, Pad }; + Q_ENUM(FillMode) FillMode fillMode() const; void setFillMode(FillMode); diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 223cb8f46f..e54f5bb9c9 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -213,15 +213,27 @@ void QQuickImageBase::load() d->devicePixelRatio = 1.0; QUrl loadUrl = d->url; - if (d->url.scheme() == QStringLiteral("image") - || d->url.toString().endsWith(QLatin1String(".svg")) - || d->url.toString().endsWith(QLatin1String(".svgz"))) { - // QQuickImageProvider and SVG can generate a high resolution image when - // sourceSize is set. If sourceSize is not set then the provider default size - // will be used, as usual. - if (!d->sourcesize.isEmpty()) + + // QQuickImageProvider and SVG can generate a high resolution image when + // sourceSize is set. If sourceSize is not set then the provider default size + // will be used, as usual. + bool setDevicePixelRatio = false; + if (!d->sourcesize.isValid()) { + if (loadUrl.scheme() == QStringLiteral("image")) { + setDevicePixelRatio = true; + } else { + QString stringUrl = loadUrl.toString(); + if (stringUrl.endsWith(QLatin1String("svg")) || + stringUrl.endsWith(QLatin1String("svgz"))) { + setDevicePixelRatio = true; + } + } + + if (setDevicePixelRatio) d->devicePixelRatio = targetDevicePixelRatio; - } else { + } + + if (!setDevicePixelRatio) { // (possible) local file: loadUrl and d->devicePixelRatio will be modified if // an "@2x" file is found. resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); @@ -368,7 +380,7 @@ void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixe // Look for an @2x version QString localFile2x = image2xPath(localFile); - if (!QFile(localFile2x).exists()) + if (!QFile::exists(localFile2x)) return; // @2x file found found: Change url and devicePixelRatio diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h index 4fcfaecd7d..98943a235c 100644 --- a/src/quick/items/qquickimagebase_p.h +++ b/src/quick/items/qquickimagebase_p.h @@ -43,7 +43,6 @@ class QQuickImageBasePrivate; class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(Status) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -57,6 +56,7 @@ public: QQuickImageBase(QQuickItem *parent=0); ~QQuickImageBase(); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; qreal progress() const; diff --git a/src/quick/items/qquickimplicitsizeitem_p_p.h b/src/quick/items/qquickimplicitsizeitem_p_p.h index f2e502af15..d606474e9d 100644 --- a/src/quick/items/qquickimplicitsizeitem_p_p.h +++ b/src/quick/items/qquickimplicitsizeitem_p_p.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE -class QQuickImplicitSizeItemPrivate : public QQuickItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickImplicitSizeItemPrivate : public QQuickItemPrivate { Q_DECLARE_PUBLIC(QQuickImplicitSizeItem) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 3d0f550d14..94b89d0fc4 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -1304,8 +1304,8 @@ void QQuickKeysAttached::setPriority(Priority order) void QQuickKeysAttached::componentComplete() { - Q_D(QQuickKeysAttached); #ifndef QT_NO_IM + Q_D(QQuickKeysAttached); if (d->item) { for (int ii = 0; ii < d->targets.count(); ++ii) { QQuickItem *targetItem = d->targets.at(ii); @@ -2776,7 +2776,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c) window = c; if (polishScheduled) - QQuickWindowPrivate::get(window)->itemsToPolish.insert(q); + QQuickWindowPrivate::get(window)->itemsToPolish.append(q); if (!parentItem) QQuickWindowPrivate::get(window)->parentlessItems.insert(q); @@ -2808,7 +2808,7 @@ void QQuickItemPrivate::derefWindow() removeFromDirtyList(); QQuickWindowPrivate *c = QQuickWindowPrivate::get(window); if (polishScheduled) - c->itemsToPolish.remove(q); + c->itemsToPolish.removeOne(q); QMutableHashIterator<int, QQuickItem *> itemTouchMapIt(c->itemForTouchPointId); while (itemTouchMapIt.hasNext()) { if (itemTouchMapIt.next().value() == q) @@ -4102,7 +4102,7 @@ void QQuickItem::polish() if (d->window) { QQuickWindowPrivate *p = QQuickWindowPrivate::get(d->window); bool maybeupdate = p->itemsToPolish.isEmpty(); - p->itemsToPolish.insert(this); + p->itemsToPolish.append(this); if (maybeupdate) d->window->maybeUpdate(); } } diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 463113386b..d92910ce9c 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -141,7 +141,6 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQuickItemLayer *layer READ layer DESIGNABLE false CONSTANT FINAL) - Q_ENUMS(TransformOrigin) Q_CLASSINFO("DefaultProperty", "data") Q_CLASSINFO("qt_HasQmlAccessors", "true") @@ -187,6 +186,7 @@ public: Left, Center, Right, BottomLeft, Bottom, BottomRight }; + Q_ENUM(TransformOrigin) QQuickItem(QQuickItem *parent = 0); virtual ~QQuickItem(); diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 64d8bd0ede..c0d06da829 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -645,8 +645,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickKeyNavigationAttached : public QObject, publi Q_PROPERTY(QQuickItem *backtab READ backtab WRITE setBacktab NOTIFY backtabChanged) Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) - Q_ENUMS(Priority) - public: QQuickKeyNavigationAttached(QObject * = 0); @@ -664,6 +662,7 @@ public: void setBacktab(QQuickItem *); enum Priority { BeforeItem, AfterItem }; + Q_ENUM(Priority) Priority priority() const; void setPriority(Priority); @@ -739,8 +738,6 @@ class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter Q_PROPERTY(QQmlListProperty<QQuickItem> forwardTo READ forwardTo) Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) - Q_ENUMS(Priority) - public: QQuickKeysAttached(QObject *parent=0); ~QQuickKeysAttached(); @@ -755,6 +752,7 @@ public: } enum Priority { BeforeItem, AfterItem}; + Q_ENUM(Priority) Priority priority() const; void setPriority(Priority); diff --git a/src/quick/items/qquickitemanimation_p.h b/src/quick/items/qquickitemanimation_p.h index 907687a2bd..9f0b3dccb8 100644 --- a/src/quick/items/qquickitemanimation_p.h +++ b/src/quick/items/qquickitemanimation_p.h @@ -136,7 +136,7 @@ public: BottomFirst, TopFirst }; - Q_ENUMS(Orientation) + Q_ENUM(Orientation) int duration() const; void setDuration(int); diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 5fbae66b6c..8a6766770e 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -158,11 +158,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickPathView>(uri,major,minor,"PathView"); qmlRegisterUncreatableType<QQuickBasePositioner>(uri,major,minor,"Positioner", QStringLiteral("Positioner is an abstract type that is only available as an attached property.")); -#ifndef QT_NO_VALIDATOR - qmlRegisterType<QQuickIntValidator>(uri,major,minor,"IntValidator"); - qmlRegisterType<QQuickDoubleValidator>(uri,major,minor,"DoubleValidator"); - qmlRegisterType<QRegExpValidator>(uri,major,minor,"RegExpValidator"); -#endif qmlRegisterType<QQuickRectangle>(uri,major,minor,"Rectangle"); qmlRegisterType<QQuickRepeater>(uri,major,minor,"Repeater"); qmlRegisterType<QQuickRow>(uri,major,minor,"Row"); @@ -190,9 +185,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickCurve>(); qmlRegisterType<QQuickScaleGrid>(); qmlRegisterType<QQuickTextLine>(); -#ifndef QT_NO_VALIDATOR - qmlRegisterType<QValidator>(); -#endif qmlRegisterType<QQuickPen>(); qmlRegisterType<QQuickFlickableVisibleArea>(); qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine"); @@ -269,6 +261,16 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea"); qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image"); qmlRegisterType<QQuickMouseArea, 2>(uri, 2, 5, "MouseArea"); + + qmlRegisterType<QQuickText, 6>(uri, 2, 6, "Text"); + qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit"); + qmlRegisterType<QQuickTextInput, 6>(uri, 2, 6, "TextInput"); + qmlRegisterUncreatableType<QQuickBasePositioner, 6>(uri, 2, 6, "Positioner", + QStringLiteral("Positioner is an abstract type that is only available as an attached property.")); + qmlRegisterType<QQuickColumn, 6>(uri, 2, 6, "Column"); + qmlRegisterType<QQuickRow, 6>(uri, 2, 6, "Row"); + qmlRegisterType<QQuickGrid, 6>(uri, 2, 6, "Grid"); + qmlRegisterType<QQuickFlow, 6>(uri, 2, 6, "Flow"); } static void initResources() diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 01ef1e65f7..7a55bd6e0a 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -71,19 +71,19 @@ FxViewItem::~FxViewItem() qreal FxViewItem::itemX() const { - return transitionableItem ? transitionableItem->itemX() : item->x(); + return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0); } qreal FxViewItem::itemY() const { - return transitionableItem ? transitionableItem->itemY() : item->y(); + return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0); } void FxViewItem::moveTo(const QPointF &pos, bool immediate) { if (transitionableItem) transitionableItem->moveTo(pos, immediate); - else + else if (item) item->setPosition(pos); } @@ -91,21 +91,26 @@ void FxViewItem::setVisible(bool visible) { if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning()) return; - QQuickItemPrivate::get(item)->setCulled(!visible); + if (item) + QQuickItemPrivate::get(item)->setCulled(!visible); } void FxViewItem::trackGeometry(bool track) { if (track) { if (!trackGeom) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + if (item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + } trackGeom = true; } } else { if (trackGeom) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + if (item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + } trackGeom = false; } } @@ -1199,7 +1204,7 @@ void QQuickItemView::destroyRemoved() for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end();) { FxViewItem *item = *it; - if (item->index == -1 && item->attached->delayRemove() == false) { + if (item->index == -1 && (!item->attached || item->attached->delayRemove() == false)) { if (d->transitioner && d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) { // don't remove from visibleItems until next layout() d->runDelayedRemoveTransition = true; @@ -1344,7 +1349,7 @@ void QQuickItemView::geometryChanged(const QRectF &newGeometry, const QRectF &ol { Q_D(QQuickItemView); d->markExtentsDirty(); - if (isComponentComplete() && d->isValid()) + if (isComponentComplete() && (d->isValid() || !d->visibleItems.isEmpty())) d->forceLayoutPolish(); QQuickFlickable::geometryChanged(newGeometry, oldGeometry); } @@ -1641,7 +1646,8 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex) applyPendingChanges(); if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) { if (currentItem) { - currentItem->attached->setIsCurrentItem(false); + if (currentItem->attached) + currentItem->attached->setIsCurrentItem(false); releaseItem(currentItem); currentItem = 0; currentIndex = modelIndex; @@ -1664,11 +1670,12 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex) int oldCurrentIndex = currentIndex; currentIndex = modelIndex; currentItem = createItem(modelIndex, false); - if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) + if (oldCurrentItem && oldCurrentItem->attached && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { currentItem->item->setFocus(true); - currentItem->attached->setIsCurrentItem(true); + if (currentItem->attached) + currentItem->attached->setIsCurrentItem(true); initializeCurrentItem(); } @@ -1806,7 +1813,7 @@ void QQuickItemViewPrivate::updateViewport() { Q_Q(QQuickItemView); qreal extra = headerSize() + footerSize(); - qreal contentSize = isValid() ? (endPosition() - startPosition()) : 0.0; + qreal contentSize = isValid() || !visibleItems.isEmpty() ? (endPosition() - startPosition()) : 0.0; if (layoutOrientation() == Qt::Vertical) q->setContentHeight(contentSize + extra); else @@ -1824,6 +1831,7 @@ void QQuickItemViewPrivate::layout() if (!isValid() && !visibleItems.count()) { clear(); setPosition(contentStartOffset()); + updateViewport(); if (transitioner) transitioner->setPopulateTransitionEnabled(false); inLayout = false; @@ -1967,7 +1975,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult QQmlChangeSet::Change removal; for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end();) { FxViewItem *item = *it; - if (item->index == -1 && !item->attached->delayRemove()) { + if (item->index == -1 && (!item->attached || !item->attached->delayRemove())) { removeItem(item, removal, &removalResult); removedCount++; it = visibleItems.erase(it); @@ -2007,8 +2015,10 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult } itemCount += insertions[i].count; } - for (int i=0; i<newItems.count(); i++) - newItems.at(i)->attached->emitAdd(); + for (int i=0; i<newItems.count(); i++) { + if (newItems.at(i)->attached) + newItems.at(i)->attached->emitAdd(); + } // for each item that was moved directly into the view as a result of a move(), // find the index it was moved from in order to set its initial position, so that we @@ -2040,7 +2050,8 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult if (currentChanges.currentChanged) { if (currentChanges.currentRemoved && currentItem) { - currentItem->attached->setIsCurrentItem(false); + if (currentItem->item && currentItem->attached) + currentItem->attached->setIsCurrentItem(false); releaseItem(currentItem); currentItem = 0; } @@ -2092,10 +2103,10 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Change &remo } else { // removed item visibleAffected = true; - if (!removal.isMove()) + if (!removal.isMove() && item->item && item->attached) item->attached->emitRemove(); - if (item->attached->delayRemove() && !removal.isMove()) { + if (item->item && item->attached && item->attached->delayRemove() && !removal.isMove()) { item->index = -1; QObject::connect(item->attached, SIGNAL(delayRemoveChanged()), q, SLOT(destroyRemoved()), Qt::QueuedConnection); ++it; @@ -2352,12 +2363,14 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item) item->trackGeometry(false); QQmlInstanceModel::ReleaseFlags flags = model->release(item->item); - if (flags == 0) { - // item was not destroyed, and we no longer reference it. - QQuickItemPrivate::get(item->item)->setCulled(true); - unrequestedItems.insert(item->item, model->indexOf(item->item, q)); - } else if (flags & QQmlInstanceModel::Destroyed) { - item->item->setParentItem(0); + if (item->item) { + if (flags == 0) { + // item was not destroyed, and we no longer reference it. + QQuickItemPrivate::get(item->item)->setCulled(true); + unrequestedItems.insert(item->item, model->indexOf(item->item, q)); + } else if (flags & QQmlInstanceModel::Destroyed) { + item->item->setParentItem(0); + } } delete item; return flags != QQmlInstanceModel::Referenced; @@ -2421,7 +2434,7 @@ void QQuickItemViewPrivate::updateUnrequestedIndexes() void QQuickItemViewPrivate::updateUnrequestedPositions() { - for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.begin(), cend = unrequestedItems.end(); it != cend; ++it) + for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.cbegin(), cend = unrequestedItems.cend(); it != cend; ++it) repositionPackageItemAt(it.key(), it.value()); } diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 6e5ae032c2..3e28ff336d 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -88,11 +88,6 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd) Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged) - Q_ENUMS(HighlightRangeMode) - Q_ENUMS(PositionMode) - Q_ENUMS(VerticalLayoutDirection) - Q_ENUMS(LayoutDirection) - public: // this holds all layout enum values so they can be referred to by other enums // to ensure consistent values - e.g. QML references to GridView.TopToBottom flow @@ -103,11 +98,13 @@ public: VerticalTopToBottom, VerticalBottomToTop }; + Q_ENUM(LayoutDirection) enum VerticalLayoutDirection { TopToBottom = VerticalTopToBottom, BottomToTop = VerticalBottomToTop }; + Q_ENUM(VerticalLayoutDirection) QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent = 0); ~QQuickItemView(); @@ -185,6 +182,7 @@ public: virtual void setHighlightFollowsCurrentItem(bool); enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange }; + Q_ENUM(HighlightRangeMode) HighlightRangeMode highlightRangeMode() const; void setHighlightRangeMode(HighlightRangeMode mode); @@ -200,6 +198,7 @@ public: virtual void setHighlightMoveDuration(int); enum PositionMode { Beginning, Center, End, Visible, Contain, SnapPosition }; + Q_ENUM(PositionMode) Q_INVOKABLE void positionViewAtIndex(int index, int mode); Q_INVOKABLE int indexAt(qreal x, qreal y) const; diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 5ac88a7585..67ef413d31 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -53,6 +53,8 @@ public: qreal itemX() const; qreal itemY() const; + inline qreal itemWidth() const { return item ? item->width() : 0; } + inline qreal itemHeight() const { return item ? item->height() : 0; } void moveTo(const QPointF &pos, bool immediate); void setVisible(bool visible); @@ -75,7 +77,7 @@ public: virtual bool contains(qreal x, qreal y) const = 0; - QQuickItem *item; + QPointer<QQuickItem> item; QQuickItemView *view; QQuickItemViewTransitionableItem *transitionableItem; QQuickItemViewAttached *attached; diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 7fa6cdc161..6fa299bf03 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -34,6 +34,7 @@ #include "qquickitemviewtransition_p.h" #include <QtQuick/qquickitem.h> #include <QtQuick/private/qquicktransition_p.h> +#include <QtQuick/private/qquicktransitionmanager_p_p.h> QT_BEGIN_NAMESPACE diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 170072a814..6f93697cc5 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -34,16 +34,20 @@ #ifndef QQUICKITEMVIEWTRANSITION_P_P_H #define QQUICKITEMVIEWTRANSITION_P_P_H -#include <private/qquicktransitionmanager_p_p.h> +#include <QtQuick/private/qtquickglobal_p.h> +#include <QtCore/qobject.h> +#include <QtCore/qpoint.h> +#include <QtQml/qqml.h> QT_BEGIN_NAMESPACE class QQuickItem; +class QQuickTransition; class QQuickItemViewTransitionableItem; class QQuickItemViewTransitionJob; -class QQuickItemViewTransitionChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitionChangeListener { public: QQuickItemViewTransitionChangeListener() {} @@ -53,7 +57,7 @@ public: }; -class QQuickItemViewTransitioner +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitioner { public: enum TransitionType { @@ -113,7 +117,7 @@ private: /* An item that can be transitioned using QQuickViewTransitionJob. */ -class QQuickItemViewTransitionableItem +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitionableItem { public: QQuickItemViewTransitionableItem(QQuickItem *i); diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index cc500956f5..a2920f8bad 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -267,18 +267,18 @@ public: } qreal itemPosition() const { if (view->orientation() == QQuickListView::Vertical) - return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY()); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemHeight()-itemY() : itemY()); else - return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX()); + return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemWidth()-itemX() : itemX()); } qreal size() const { if (section()) - return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight()+section()->height() : itemWidth()+section()->width()); else - return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth()); } qreal itemSize() const { - return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth()); } qreal sectionSize() const { if (section()) @@ -289,11 +289,11 @@ public: if (view->orientation() == QQuickListView::Vertical) { return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemY() - : itemY() + item->height()); + : itemY() + itemHeight()); } else { return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemX() - : itemX() + item->width()); + : itemX() + itemWidth()); } } void setPosition(qreal pos, bool immediate = false) { @@ -320,8 +320,8 @@ public: item->setWidth(size); } bool contains(qreal x, qreal y) const Q_DECL_OVERRIDE { - return (x >= itemX() && x < itemX() + item->width() && - y >= itemY() && y < itemY() + item->height()); + return (x >= itemX() && x < itemX() + itemWidth() && + y >= itemY() && y < itemY() + itemHeight()); } QQuickListView *view; @@ -332,7 +332,7 @@ private: if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { if (section()) pos += section()->height(); - return QPointF(itemX(), -item->height() - pos); + return QPointF(itemX(), -itemHeight() - pos); } else { if (section()) pos += section()->height(); @@ -342,7 +342,7 @@ private: if (view->effectiveLayoutDirection() == Qt::RightToLeft) { if (section()) pos += section()->width(); - return QPointF(-item->width() - pos, itemY()); + return QPointF(-itemWidth() - pos, itemY()); } else { if (section()) pos += section()->width(); @@ -427,14 +427,24 @@ qreal QQuickListViewPrivate::lastPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) { - int invisibleCount = visibleItems.count() - visibleIndex; + int invisibleCount = INT_MIN; + int delayRemovedCount = 0; for (int i = visibleItems.count()-1; i >= 0; --i) { if (visibleItems.at(i)->index != -1) { - invisibleCount = model->count() - visibleItems.at(i)->index - 1; + // Find the invisible count after the last visible item with known index + invisibleCount = model->count() - (visibleItems.at(i)->index + 1 + delayRemovedCount); break; + } else if (visibleItems.at(i)->attached->delayRemove()) { + ++delayRemovedCount; } } - pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing); + if (invisibleCount == INT_MIN) { + // All visible items are in delayRemove state + invisibleCount = model->count(); + } + pos = (*(--visibleItems.constEnd()))->endPosition(); + if (invisibleCount > 0) + pos += invisibleCount * (averageSize + spacing); } else if (model && model->count()) { pos = (model->count() * averageSize + (model->count()-1) * spacing); } @@ -602,7 +612,7 @@ bool QQuickListViewPrivate::releaseItem(FxViewItem *item) QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached); bool released = QQuickItemViewPrivate::releaseItem(item); - if (released && att && att->m_sectionItem) { + if (released && item->item && att && att->m_sectionItem) { // We hold no more references to this item int i = 0; do { @@ -657,10 +667,11 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal while (modelIndex < model->count() && pos <= fillTo) { if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer)))) break; - qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer << "item" << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer << "item" << (QObject *)(item->item); if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(pos, true); - QQuickItemPrivate::get(item->item)->setCulled(doBuffer); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(doBuffer); pos += item->size() + spacing; visibleItems.append(item); ++modelIndex; @@ -673,12 +684,13 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) { if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer)))) break; - qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer << "item" << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer << "item" << (QObject *)(item->item); --visibleIndex; visiblePos -= item->size() + spacing; if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(visiblePos, true); - QQuickItemPrivate::get(item->item)->setCulled(doBuffer); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(doBuffer); visibleItems.prepend(item); changed = true; } @@ -709,7 +721,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer visibleIndex++; visibleItems.removeAt(index); if (item->transitionScheduledOrRunning()) { - qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << (QObject *)(item->item); item->releaseAfterTransition = true; releasePendingTransition.append(item); } else { @@ -728,10 +740,10 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) { if (item->attached->delayRemove()) break; - qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position() << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position() << (QObject *)(item->item); visibleItems.removeLast(); if (item->transitionScheduledOrRunning()) { - qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << (QObject *)(item->item); item->releaseAfterTransition = true; releasePendingTransition.append(item); } else { @@ -2844,7 +2856,8 @@ void QQuickListView::viewportMoved(Qt::Orientations orient) qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd; for (int i = 0; i < d->visibleItems.count(); ++i) { FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i)); - QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to); } if (d->currentItem) QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to); diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h index bcb4e18751..7f64e12bba 100644 --- a/src/quick/items/qquicklistview_p.h +++ b/src/quick/items/qquicklistview_p.h @@ -47,8 +47,6 @@ class Q_AUTOTEST_EXPORT QQuickViewSection : public QObject Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY criteriaChanged) Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(int labelPositioning READ labelPositioning WRITE setLabelPositioning NOTIFY labelPositioningChanged) - Q_ENUMS(SectionCriteria) - Q_ENUMS(LabelPositioning) public: QQuickViewSection(QQuickListView *parent=0); @@ -56,6 +54,7 @@ public: void setProperty(const QString &); enum SectionCriteria { FullString, FirstCharacter }; + Q_ENUM(SectionCriteria) SectionCriteria criteria() const { return m_criteria; } void setCriteria(SectionCriteria); @@ -65,6 +64,7 @@ public: QString sectionString(const QString &value); enum LabelPositioning { InlineLabels = 0x01, CurrentLabelAtStart = 0x02, NextLabelAtEnd = 0x04 }; + Q_ENUM(LabelPositioning) int labelPositioning() { return m_labelPositioning; } void setLabelPositioning(int pos); @@ -106,10 +106,6 @@ class Q_AUTOTEST_EXPORT QQuickListView : public QQuickItemView Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 2) Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 2) - Q_ENUMS(Orientation) - Q_ENUMS(SnapMode) - Q_ENUMS(HeaderPositioning) - Q_ENUMS(FooterPositioning) Q_CLASSINFO("DefaultProperty", "data") public: @@ -120,6 +116,7 @@ public: void setSpacing(qreal spacing); enum Orientation { Horizontal = Qt::Horizontal, Vertical = Qt::Vertical }; + Q_ENUM(Orientation) Orientation orientation() const; void setOrientation(Orientation); @@ -140,14 +137,17 @@ public: void setHighlightMoveDuration(int) Q_DECL_OVERRIDE; enum SnapMode { NoSnap, SnapToItem, SnapOneItem }; + Q_ENUM(SnapMode) SnapMode snapMode() const; void setSnapMode(SnapMode mode); enum HeaderPositioning { InlineHeader, OverlayHeader, PullBackHeader }; + Q_ENUM(HeaderPositioning) HeaderPositioning headerPositioning() const; void setHeaderPositioning(HeaderPositioning positioning); enum FooterPositioning { InlineFooter, OverlayFooter, PullBackFooter }; + Q_ENUM(FooterPositioning) FooterPositioning footerPositioning() const; void setFooterPositioning(FooterPositioning positioning); diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index dd04568db2..df09780895 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -943,7 +943,7 @@ QV4::ReturnedValue QQuickLoaderPrivate::extractInitialPropertyValues(QQmlV4Funct QV4::ScopedValue valuemap(scope, QV4::Primitive::undefinedValue()); if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); - if (!v->isObject() || v->asArrayObject()) { + if (!v->isObject() || v->as<QV4::ArrayObject>()) { *error = true; qmlInfo(loader) << QQuickLoader::tr("setSource: value is not an object"); } else { diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h index 2c0e98de59..6ed4f2437b 100644 --- a/src/quick/items/qquickloader_p.h +++ b/src/quick/items/qquickloader_p.h @@ -42,7 +42,6 @@ class QQuickLoaderPrivate; class Q_AUTOTEST_EXPORT QQuickLoader : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(Status) Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -69,6 +68,7 @@ public: void resetSourceComponent(); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; qreal progress() const; diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index 621419d1a7..fb1263f0bd 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -50,7 +50,7 @@ #include "qquickitemchangelistener_p.h" #include <qqmlincubator.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/quick/items/qquickopenglinfo_p.h b/src/quick/items/qquickopenglinfo_p.h index 2a2e2a719b..511413c814 100644 --- a/src/quick/items/qquickopenglinfo_p.h +++ b/src/quick/items/qquickopenglinfo_p.h @@ -63,7 +63,6 @@ class QQuickOpenGLInfo : public QObject Q_PROPERTY(int minorVersion READ minorVersion NOTIFY minorVersionChanged FINAL) Q_PROPERTY(ContextProfile profile READ profile NOTIFY profileChanged FINAL) Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL) - Q_ENUMS(ContextProfile RenderableType) public: QQuickOpenGLInfo(QQuickItem *item = 0); @@ -77,6 +76,7 @@ public: CoreProfile = QSurfaceFormat::CoreProfile, CompatibilityProfile = QSurfaceFormat::CompatibilityProfile }; + Q_ENUM(ContextProfile) ContextProfile profile() const; // keep in sync with QSurfaceFormat::RenderableType @@ -85,6 +85,7 @@ public: OpenGL = QSurfaceFormat::OpenGL, OpenGLES = QSurfaceFormat::OpenGLES }; + Q_ENUM(RenderableType) RenderableType renderableType() const; static QQuickOpenGLInfo *qmlAttachedProperties(QObject *object); diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index 356e4a46f6..28eb3398a0 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -43,7 +43,6 @@ class QQuickPaintedItemPrivate; class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem { Q_OBJECT - Q_ENUMS(RenderTarget) Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize NOTIFY contentsSizeChanged) Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged) @@ -58,6 +57,7 @@ public: FramebufferObject, InvertedYFramebufferObject }; + Q_ENUM(RenderTarget) enum PerformanceHint { FastFBOResizing = 0x1 diff --git a/src/quick/items/qquickpainteditem_p.h b/src/quick/items/qquickpainteditem_p.h index 3712e964f8..2759d9d683 100644 --- a/src/quick/items/qquickpainteditem_p.h +++ b/src/quick/items/qquickpainteditem_p.h @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE class QQuickPaintedItemTextureProvider; class QSGPainterNode; -class QQuickPaintedItemPrivate : public QQuickItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickPaintedItemPrivate : public QQuickItemPrivate { public: QQuickPaintedItemPrivate(); diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index 58605f79dd..302532c3d1 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -98,7 +98,7 @@ QQuickPathViewPrivate::QQuickPathViewPrivate() , inRefill(false) , dragMargin(0), deceleration(100), maximumFlickVelocity(QML_FLICK_DEFAULTMAXVELOCITY) , moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset), flickDuration(0) - , firstIndex(-1), pathItems(-1), requestedIndex(-1), cacheSize(0), requestedZ(0) + , pathItems(-1), requestedIndex(-1), cacheSize(0), requestedZ(0) , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0) , moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition) , highlightPosition(0) @@ -447,7 +447,6 @@ void QQuickPathViewPrivate::regenerate() if (!isValid()) return; - firstIndex = -1; updateMappedRange(); q->refill(); } @@ -1473,7 +1472,7 @@ int QQuickPathView::indexAt(qreal x, qreal y) const QQuickItem *item = d->items.at(idx); QPointF p = item->mapFromItem(this, QPointF(x, y)); if (item->contains(p)) - return (d->firstIndex + idx) % d->modelCount; + return d->model->indexOf(item, 0); } return -1; @@ -1896,12 +1895,12 @@ void QQuickPathView::refill() int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount); // first move existing items and remove items off path - int idx = d->firstIndex; - qCDebug(lcItemViewDelegateLifecycle) << "firstIndex" << idx << "currentIndex" << d->currentIndex << "offset" << d->offset; + qCDebug(lcItemViewDelegateLifecycle) << "currentIndex" << d->currentIndex << "offset" << d->offset; QList<QQuickItem*>::iterator it = d->items.begin(); while (it != d->items.end()) { - qreal pos = d->positionOfIndex(idx); QQuickItem *item = *it; + int idx = d->model->indexOf(item, 0); + qreal pos = d->positionOfIndex(idx); if (lcItemViewDelegateLifecycle().isDebugEnabled()) { QQuickText *text = qmlobject_cast<QQuickText*>(item); if (text) @@ -1923,81 +1922,140 @@ void QQuickPathView::refill() if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) { qCDebug(lcItemViewDelegateLifecycle) << "release" << idx << "@" << pos << ", !isInBound: lower" << (d->mappedRange - d->mappedCache) << "upper" << (1.0 + d->mappedCache); d->releaseItem(item); - if (it == d->items.begin()) { - if (++d->firstIndex >= d->modelCount) { - d->firstIndex = 0; - } - } it = d->items.erase(it); } else { ++it; } } - ++idx; - if (idx >= d->modelCount) - idx = 0; } - if (!d->items.count()) - d->firstIndex = -1; - bool waiting = false; if (d->modelCount) { - // add items to beginning and end + // add items as needed if (d->items.count() < count+d->cacheSize) { - int idx = qRound(d->modelCount - d->offset) % d->modelCount; + int endIdx = 0; + qreal endPos; + int startIdx = 0; qreal startPos = 0.0; - if (d->haveHighlightRange && (d->highlightRangeMode != QQuickPathView::NoHighlightRange - || d->snapMode != QQuickPathView::NoSnap)) - startPos = d->highlightRangeStart; - if (d->firstIndex >= 0) { - startPos = d->positionOfIndex(d->firstIndex); - idx = (d->firstIndex + d->items.count()) % d->modelCount; + if (d->items.count()) { + //Find the beginning and end, items may not be in sorted order + endPos = -1.0; + startPos = 2.0; + + for (int i = 0; i < d->items.count(); i++) { + int idx = d->model->indexOf(d->items[i], 0); + qreal curPos = d->positionOfIndex(idx); + if (curPos > endPos) { + endPos = curPos; + endIdx = idx; + } + + if (curPos < startPos) { + startPos = curPos; + startIdx = idx; + } + } + } else { + if (d->haveHighlightRange + && (d->highlightRangeMode != QQuickPathView::NoHighlightRange + || d->snapMode != QQuickPathView::NoSnap)) + startPos = d->highlightRangeStart; + // With no items, then "end" is just off the top so we populate via append + endIdx = (qRound(d->modelCount - d->offset) - 1) % d->modelCount; + endPos = d->positionOfIndex(endIdx); } - qreal pos = d->positionOfIndex(idx); - while ((d->isInBound(pos, startPos, 1.0 + d->mappedCache) || !d->items.count()) && d->items.count() < count+d->cacheSize) { - qCDebug(lcItemViewDelegateLifecycle) << "append" << idx << "@" << pos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); - QQuickItem *item = d->getItem(idx, idx+1, pos >= 1.0); + //Append + int idx = endIdx + 1; + if (idx >= d->modelCount) + idx = 0; + qreal nextPos = d->positionOfIndex(idx); + while ((d->isInBound(nextPos, endPos, 1.0 + d->mappedCache) || !d->items.count()) + && d->items.count() < count+d->cacheSize) { + qCDebug(lcItemViewDelegateLifecycle) << "append" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); if (!item) { waiting = true; break; } + if (d->items.contains(item)) { + break; //Otherwise we'd "re-add" it, and get confused + } if (d->currentIndex == idx) { currentVisible = true; - d->currentItemOffset = pos; + d->currentItemOffset = nextPos; } - if (d->items.count() == 0) - d->firstIndex = idx; d->items.append(item); - d->updateItem(item, pos); + d->updateItem(item, nextPos); + endIdx = idx; + endPos = nextPos; ++idx; if (idx >= d->modelCount) idx = 0; - pos = d->positionOfIndex(idx); + nextPos = d->positionOfIndex(idx); } - idx = d->firstIndex - 1; + //Prepend + idx = startIdx - 1; if (idx < 0) idx = d->modelCount - 1; - pos = d->positionOfIndex(idx); - while (!waiting && d->isInBound(pos, d->mappedRange - d->mappedCache, startPos) && d->items.count() < count+d->cacheSize) { - qCDebug(lcItemViewDelegateLifecycle) << "prepend" << idx << "@" << pos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); - QQuickItem *item = d->getItem(idx, idx+1, pos >= 1.0); + nextPos = d->positionOfIndex(idx); + while (!waiting && d->isInBound(nextPos, d->mappedRange - d->mappedCache, startPos) + && d->items.count() < count+d->cacheSize) { + qCDebug(lcItemViewDelegateLifecycle) << "prepend" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); if (!item) { waiting = true; break; } + if (d->items.contains(item)) { + break; //Otherwise we'd "re-add" it, and get confused + } if (d->currentIndex == idx) { currentVisible = true; - d->currentItemOffset = pos; + d->currentItemOffset = nextPos; } d->items.prepend(item); - d->updateItem(item, pos); - d->firstIndex = idx; - idx = d->firstIndex - 1; + d->updateItem(item, nextPos); + startIdx = idx; + startPos = nextPos; + --idx; if (idx < 0) idx = d->modelCount - 1; - pos = d->positionOfIndex(idx); + nextPos = d->positionOfIndex(idx); + } + + // In rare cases, when jumping around with pathCount close to modelCount, + // new items appear in the middle. This more generic addition iteration handles this + // Since this is the rare case, we try append/prepend first and only do this if + // there are gaps still left to fill. + if (!waiting && d->items.count() < count+d->cacheSize) { + qCDebug(lcItemViewDelegateLifecycle) << "Checking for pathview middle inserts, items count was" << d->items.count(); + idx = startIdx; + QQuickItem *lastItem = d->items[0]; + while (idx != endIdx) { + //This gets the reference from the delegate model, and will not re-create + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); + if (!item) { + waiting = true; + break; + } + if (!d->items.contains(item)) { //We found a hole + nextPos = d->positionOfIndex(idx); + qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); + if (d->currentIndex == idx) { + currentVisible = true; + d->currentItemOffset = nextPos; + } + int lastListIdx = d->items.indexOf(lastItem); + d->items.insert(lastListIdx + 1, item); + d->updateItem(item, nextPos); + } + + lastItem = item; + ++idx; + if (idx >= d->modelCount) + idx = 0; + } } } } @@ -2128,7 +2186,6 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset) d->offset = qmlMod(d->modelCount - d->currentIndex, d->modelCount); changedOffset = true; } - d->firstIndex = -1; d->updateMappedRange(); d->scheduleLayout(); } @@ -2185,8 +2242,16 @@ void QQuickPathViewPrivate::createCurrentItem() { if (requestedIndex != -1) return; - int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount; - if (itemIndex < items.count()) { + + bool inItems = false; + for (int i = 0; i < items.count(); i++) { + if (model->indexOf(items[i], 0) == currentIndex) { + inItems = true; + break; + } + } + + if (inItems) { if ((currentItem = getItem(currentIndex, currentIndex))) { currentItem->setFocus(true); if (QQuickPathViewAttached *att = attached(currentItem)) diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h index 8062e07795..0f2e4a956c 100644 --- a/src/quick/items/qquickpathview_p.h +++ b/src/quick/items/qquickpathview_p.h @@ -78,10 +78,6 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem Q_PROPERTY(int cacheItemCount READ cacheItemCount WRITE setCacheItemCount NOTIFY cacheItemCountChanged) - Q_ENUMS(HighlightRangeMode) - Q_ENUMS(SnapMode) - Q_ENUMS(PositionMode) - public: QQuickPathView(QQuickItem *parent=0); virtual ~QQuickPathView(); @@ -105,6 +101,7 @@ public: QQuickItem *highlightItem(); enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange }; + Q_ENUM(HighlightRangeMode) HighlightRangeMode highlightRangeMode() const; void setHighlightRangeMode(HighlightRangeMode mode); @@ -146,10 +143,12 @@ public: void setCacheItemCount(int); enum SnapMode { NoSnap, SnapToItem, SnapOneItem }; + Q_ENUM(SnapMode) SnapMode snapMode() const; void setSnapMode(SnapMode mode); enum PositionMode { Beginning, Center, End, Contain=4, SnapPosition }; // 3 == Visible in other views + Q_ENUM(PositionMode) Q_INVOKABLE void positionViewAtIndex(int index, int mode); Q_INVOKABLE int indexAt(qreal x, qreal y) const; Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const; diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h index 35ea8616a5..2a497881d4 100644 --- a/src/quick/items/qquickpathview_p_p.h +++ b/src/quick/items/qquickpathview_p_p.h @@ -155,7 +155,6 @@ public: QQuickTimeLine tl; QQuickTimeLineValueProxy<QQuickPathViewPrivate> moveOffset; int flickDuration; - int firstIndex; int pathItems; int requestedIndex; int cacheSize; diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index d2de59b5d6..602b2804cc 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -42,7 +42,6 @@ class Q_AUTOTEST_EXPORT QQuickPinch : public QObject { Q_OBJECT - Q_ENUMS(Axis) Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget) Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged) Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged) @@ -103,6 +102,7 @@ public: } enum Axis { NoDrag=0x00, XAxis=0x01, YAxis=0x02, XAndYAxis=0x03, XandYAxis=XAndYAxis }; + Q_ENUM(Axis) Axis axis() const { return m_axis; } void setAxis(Axis a) { if (a == m_axis) diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 887d317069..de2596b679 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -70,6 +70,10 @@ QQuickBasePositioner::PositionedItem::PositionedItem(QQuickItem *i) , index(-1) , isNew(false) , isVisible(true) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) { } @@ -116,6 +120,13 @@ void QQuickBasePositioner::PositionedItem::startTransition(QQuickItemViewTransit transitionableItem->startTransition(transitioner, index); } +void QQuickBasePositioner::PositionedItem::updatePadding(qreal lp, qreal tp, qreal rp, qreal bp) +{ + leftPadding = lp; + topPadding = tp; + rightPadding = rp; + bottomPadding = bp; +} QQuickBasePositioner::QQuickBasePositioner(PositionerType at, QQuickItem *parent) : QQuickImplicitSizeItem(*(new QQuickBasePositionerPrivate), parent) @@ -388,11 +399,8 @@ void QQuickBasePositioner::prePositioning() void QQuickBasePositioner::positionItem(qreal x, qreal y, PositionedItem *target) { - Q_D(QQuickBasePositioner); - if ( (target->itemX() != x || target->itemY() != y) - && d->type == Both) { + if ( target->itemX() != x || target->itemY() != y ) target->moveTo(QPointF(x, y)); - } } void QQuickBasePositioner::positionItemX(qreal x, PositionedItem *target) @@ -503,6 +511,185 @@ void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *sp } } +qreal QQuickBasePositioner::padding() const +{ + Q_D(const QQuickBasePositioner); + return d->padding(); +} + +void QQuickBasePositioner::setPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + d->setPositioningDirty(); + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickBasePositioner::resetPadding() +{ + setPadding(0); +} + +qreal QQuickBasePositioner::topPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickBasePositioner::setTopPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setTopPadding(padding); +} + +void QQuickBasePositioner::resetTopPadding() +{ + Q_D(QQuickBasePositioner); + d->setTopPadding(0, true); +} + +qreal QQuickBasePositioner::leftPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickBasePositioner::setLeftPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setLeftPadding(padding); +} + +void QQuickBasePositioner::resetLeftPadding() +{ + Q_D(QQuickBasePositioner); + d->setLeftPadding(0, true); +} + +qreal QQuickBasePositioner::rightPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickBasePositioner::setRightPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setRightPadding(padding); +} + +void QQuickBasePositioner::resetRightPadding() +{ + Q_D(QQuickBasePositioner); + d->setRightPadding(0, true); +} + +qreal QQuickBasePositioner::bottomPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickBasePositioner::setBottomPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setBottomPadding(padding); +} + +void QQuickBasePositioner::resetBottomPadding() +{ + Q_D(QQuickBasePositioner); + d->setBottomPadding(0, true); +} + +QQuickBasePositionerPrivate::ExtraData::ExtraData() + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) +{ +} + +void QQuickBasePositionerPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->topPaddingChanged(); + } +} + +void QQuickBasePositionerPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->leftPaddingChanged(); + } +} + +void QQuickBasePositionerPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->rightPaddingChanged(); + } +} + +void QQuickBasePositionerPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->bottomPaddingChanged(); + } +} + /*! \qmltype Positioner \instantiates QQuickPositionerAttached @@ -640,6 +827,16 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem) \sa Row, Grid, Flow, Positioner, ColumnLayout, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Column::padding + \qmlproperty real QtQuick::Column::topPadding + \qmlproperty real QtQuick::Column::leftPadding + \qmlproperty real QtQuick::Column::bottomPadding + \qmlproperty real QtQuick::Column::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Column::populate This property holds the transition to be run for items that are part of @@ -715,20 +912,23 @@ QQuickColumn::QQuickColumn(QQuickItem *parent) void QQuickColumn::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned - qreal voffset = 0; + qreal voffset = topPadding(); + const qreal padding = leftPadding() + rightPadding(); + contentSize->setWidth(qMax(contentSize->width(), padding)); for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; - positionItemY(voffset, &child); - contentSize->setWidth(qMax(contentSize->width(), child.item->width())); + positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); + contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); voffset += child.item->height(); voffset += spacing(); } - if (voffset != 0)//If we positioned any items, undo the spacing from the last item + if (voffset - topPadding() != 0)//If we positioned any items, undo the spacing from the last item voffset -= spacing(); - contentSize->setHeight(voffset); + contentSize->setHeight(voffset + bottomPadding()); } void QQuickColumn::reportConflictingAnchors() @@ -794,6 +994,16 @@ void QQuickColumn::reportConflictingAnchors() \sa Column, Grid, Flow, Positioner, RowLayout, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Row::padding + \qmlproperty real QtQuick::Row::topPadding + \qmlproperty real QtQuick::Row::leftPadding + \qmlproperty real QtQuick::Row::bottomPadding + \qmlproperty real QtQuick::Row::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Row::populate This property holds the transition to be run for items that are part of @@ -940,27 +1150,34 @@ void QQuickRow::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this)); - qreal hoffset = 0; + qreal hoffset1 = leftPadding(); + qreal hoffset2 = rightPadding(); + if (!d->isLeftToRight()) + qSwap(hoffset1, hoffset2); + qreal hoffset = hoffset1; + const qreal padding = topPadding() + bottomPadding(); + contentSize->setHeight(qMax(contentSize->height(), padding)); QList<qreal> hoffsets; for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; if (d->isLeftToRight()) { - positionItemX(hoffset, &child); + positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } else { hoffsets << hoffset; } - contentSize->setHeight(qMax(contentSize->height(), child.item->height())); + contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding)); hoffset += child.item->width(); hoffset += spacing(); } - if (hoffset != 0)//If we positioned any items, undo the extra spacing from the last item + if (hoffset - hoffset1 != 0)//If we positioned any items, undo the extra spacing from the last item hoffset -= spacing(); - contentSize->setWidth(hoffset); + contentSize->setWidth(hoffset + hoffset2); if (d->isLeftToRight()) return; @@ -976,7 +1193,8 @@ void QQuickRow::doPositioning(QSizeF *contentSize) for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; hoffset = end - hoffsets[acc++] - child.item->width(); - positionItemX(hoffset, &child); + positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } } @@ -1044,6 +1262,16 @@ void QQuickRow::reportConflictingAnchors() \sa Flow, Row, Column, Positioner, GridLayout, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Grid::padding + \qmlproperty real QtQuick::Grid::topPadding + \qmlproperty real QtQuick::Grid::leftPadding + \qmlproperty real QtQuick::Grid::bottomPadding + \qmlproperty real QtQuick::Grid::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Grid::populate This property holds the transition to be run for items that are part of @@ -1423,8 +1651,11 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) c = (numVisible+(m_rows-1))/m_rows; } - if (r == 0 || c == 0) - return; //Nothing to do + if (r == 0 || c == 0) { + contentSize->setHeight(topPadding() + bottomPadding()); + contentSize->setWidth(leftPadding() + rightPadding()); + return; //Nothing else to do + } QList<qreal> maxColWidth; QList<qreal> maxRowHeight; @@ -1476,6 +1707,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) widthSum += columnSpacing; widthSum += maxColWidth[j]; } + widthSum += leftPadding() + rightPadding(); qreal heightSum = 0; for (int i = 0; i < maxRowHeight.size(); i++) { @@ -1483,6 +1715,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) heightSum += rowSpacing; heightSum += maxRowHeight[i]; } + heightSum += topPadding() + bottomPadding(); contentSize->setHeight(heightSum); contentSize->setWidth(widthSum); @@ -1493,10 +1726,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) else end = widthSum; - qreal xoffset = 0; + qreal xoffset = leftPadding(); if (!d->isLeftToRight()) - xoffset = end; - qreal yoffset = 0; + xoffset = end - rightPadding(); + qreal yoffset = topPadding(); int curRow =0; int curCol =0; for (int i = 0; i < positionedItems.count(); ++i) { @@ -1518,6 +1751,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) alignYOffset += maxRowHeight[curRow] - child.item->height(); positionItem(childXOffset, alignYOffset, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); if (m_flow == LeftToRight) { if (d->isLeftToRight()) @@ -1529,9 +1763,9 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) if (!curCol) { yoffset += maxRowHeight[curRow]+rowSpacing; if (d->isLeftToRight()) - xoffset = 0; + xoffset = leftPadding(); else - xoffset = end; + xoffset = end - rightPadding(); curRow++; if (curRow>=r) break; @@ -1545,7 +1779,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) xoffset += maxColWidth[curCol]+columnSpacing; else xoffset -= maxColWidth[curCol]+columnSpacing; - yoffset = 0; + yoffset = topPadding(); curCol++; if (curCol>=c) break; @@ -1603,6 +1837,16 @@ void QQuickGrid::reportConflictingAnchors() \sa Column, Row, Grid, Positioner, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Flow::padding + \qmlproperty real QtQuick::Flow::topPadding + \qmlproperty real QtQuick::Flow::leftPadding + \qmlproperty real QtQuick::Flow::bottomPadding + \qmlproperty real QtQuick::Flow::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Flow::populate This property holds the transition to be run for items that are part of @@ -1786,23 +2030,30 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) //Precondition: All items in the positioned list have a valid item pointer and should be positioned Q_D(QQuickFlow); - qreal hoffset = 0; - qreal voffset = 0; + qreal hoffset1 = leftPadding(); + qreal hoffset2 = rightPadding(); + if (!d->isLeftToRight()) + qSwap(hoffset1, hoffset2); + qreal hoffset = hoffset1; + const qreal voffset1 = topPadding(); + qreal voffset = voffset1; qreal linemax = 0; QList<qreal> hoffsets; + contentSize->setWidth(qMax(contentSize->width(), hoffset1 + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + bottomPadding())); for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; if (d->flow == LeftToRight) { - if (widthValid() && hoffset && hoffset + child.item->width() > width()) { - hoffset = 0; + if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) { + hoffset = hoffset1; voffset += linemax + spacing(); linemax = 0; } } else { - if (heightValid() && voffset && voffset + child.item->height() > height()) { - voffset = 0; + if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) { + voffset = voffset1; hoffset += linemax + spacing(); linemax = 0; } @@ -1810,13 +2061,16 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) if (d->isLeftToRight()) { positionItem(hoffset, voffset, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } else { hoffsets << hoffset; positionItemY(voffset, &child); + child.topPadding = topPadding(); + child.bottomPadding = bottomPadding(); } - contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width())); - contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height())); + contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding())); if (d->flow == LeftToRight) { hoffset += child.item->width(); @@ -1828,6 +2082,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) linemax = qMax(linemax, child.item->width()); } } + if (d->isLeftToRight()) return; @@ -1841,6 +2096,8 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) PositionedItem &child = positionedItems[i]; hoffset = end - hoffsets[acc++] - child.item->width(); positionItemX(hoffset, &child); + child.leftPadding = leftPadding(); + child.rightPadding = rightPadding(); } } diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index ea779695eb..bc67701306 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -86,6 +86,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBasePositioner : public QQuickImplicitSizeIte Q_PROPERTY(QQuickTransition *populate READ populate WRITE setPopulate NOTIFY populateChanged) Q_PROPERTY(QQuickTransition *move READ move WRITE setMove NOTIFY moveChanged) Q_PROPERTY(QQuickTransition *add READ add WRITE setAdd NOTIFY addChanged) + + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) public: enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 }; @@ -108,6 +114,26 @@ public: void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + protected: QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent); void componentComplete() Q_DECL_OVERRIDE; @@ -120,6 +146,11 @@ Q_SIGNALS: void populateChanged(); void moveChanged(); void addChanged(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); protected Q_SLOTS: void prePositioning(); @@ -144,11 +175,18 @@ protected: bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds); void startTransition(QQuickItemViewTransitioner *transitioner); + void updatePadding(qreal lp, qreal tp, qreal rp, qreal bp); + QQuickItem *item; QQuickItemViewTransitionableItem *transitionableItem; int index; bool isNew; bool isVisible; + + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; }; QPODVector<PositionedItem,8> positionedItems; @@ -236,8 +274,8 @@ public: void setColumnSpacing(qreal); void resetColumnSpacing() { m_useColumnSpacing = false; } - Q_ENUMS(Flow) enum Flow { LeftToRight, TopToBottom }; + Q_ENUM(Flow) Flow flow() const; void setFlow(Flow); @@ -245,14 +283,14 @@ public: void setLayoutDirection (Qt::LayoutDirection); Qt::LayoutDirection effectiveLayoutDirection() const; - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter}; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) HAlignment hItemAlign() const; void setHItemAlign(HAlignment align); @@ -301,8 +339,8 @@ class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner public: QQuickFlow(QQuickItem *parent=0); - Q_ENUMS(Flow) enum Flow { LeftToRight, TopToBottom }; + Q_ENUM(Flow) Flow flow() const; void setFlow(Flow); diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h index 3a8fe20351..6e1e15d4ef 100644 --- a/src/quick/items/qquickpositioners_p_p.h +++ b/src/quick/items/qquickpositioners_p_p.h @@ -51,6 +51,7 @@ #include <QtQuick/private/qquickstate_p.h> #include <private/qquicktransitionmanager_p_p.h> #include <private/qquickstatechangescript_p.h> +#include <private/qlazilyallocated_p.h> #include <QtCore/qobject.h> #include <QtCore/qstring.h> @@ -65,10 +66,26 @@ class QQuickBasePositionerPrivate : public QQuickImplicitSizeItemPrivate, public Q_DECLARE_PUBLIC(QQuickBasePositioner) public: + struct ExtraData { + ExtraData(); + + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; + }; + QLazilyAllocated<ExtraData> extra; + QQuickBasePositionerPrivate() : spacing(0), type(QQuickBasePositioner::None) , transitioner(0), positioningDirty(false) , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) + { } @@ -149,6 +166,12 @@ public: virtual void effectiveLayoutDirectionChange() { } + + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp index 0168d73c8f..5333ad2f08 100644 --- a/src/quick/items/qquickrepeater.cpp +++ b/src/quick/items/qquickrepeater.cpp @@ -50,6 +50,7 @@ QQuickRepeaterPrivate::QQuickRepeaterPrivate() , delegateValidated(false) , itemCount(0) { + setTransparentForPositioner(true); } QQuickRepeaterPrivate::~QQuickRepeaterPrivate() @@ -397,9 +398,17 @@ void QQuickRepeaterPrivate::requestItems() void QQuickRepeater::createdItem(int index, QObject *) { Q_D(QQuickRepeater); + QObject *object = d->model->object(index, false); + QQuickItem *item = qmlobject_cast<QQuickItem*>(object); + emit itemAdded(index, item); +} + +void QQuickRepeater::initItem(int index, QObject *object) +{ + Q_D(QQuickRepeater); + QQuickItem *item = qmlobject_cast<QQuickItem*>(object); + if (!d->deletables.at(index)) { - QObject *object = d->model->object(index, false); - QQuickItem *item = qmlobject_cast<QQuickItem*>(object); if (!item) { if (object) { d->model->release(object); @@ -425,17 +434,9 @@ void QQuickRepeater::createdItem(int index, QObject *) } item->stackBefore(after); } - emit itemAdded(index, item); } } -void QQuickRepeater::initItem(int, QObject *object) -{ - QQuickItem *item = qmlobject_cast<QQuickItem*>(object); - if (item) - item->setParentItem(parentItem()); -} - void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset) { Q_D(QQuickRepeater); diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h index 7e0c021c19..b12da7a706 100644 --- a/src/quick/items/qquickscalegrid_p_p.h +++ b/src/quick/items/qquickscalegrid_p_p.h @@ -47,7 +47,6 @@ QT_BEGIN_NAMESPACE class QQuickScaleGrid : public QObject { Q_OBJECT - Q_ENUMS(TileRule) Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged) Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged) diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index 1c60d9feaa..75a8319615 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -92,8 +92,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem Q_PROPERTY(QString log READ log NOTIFY logChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1) - Q_ENUMS(CullMode) - Q_ENUMS(Status) public: enum CullMode @@ -102,6 +100,7 @@ public: BackFaceCulling = QQuickShaderEffectMaterial::BackFaceCulling, FrontFaceCulling = QQuickShaderEffectMaterial::FrontFaceCulling }; + Q_ENUM(CullMode) enum Status { @@ -109,6 +108,7 @@ public: Uncompiled, Error }; + Q_ENUM(Status) QQuickShaderEffect(QQuickItem *parent = 0); ~QQuickShaderEffect(); diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp index de6cae0ea6..b84a4adaab 100644 --- a/src/quick/items/qquickshadereffectnode.cpp +++ b/src/quick/items/qquickshadereffectnode.cpp @@ -83,7 +83,9 @@ QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectM , m_compiled(false) , m_initialized(false) { - for (int i = 0; i < m_attributes.count(); ++i) + const int attributesCount = m_attributes.count(); + m_attributeNames.reserve(attributesCount + 1); + for (int i = 0; i < attributesCount; ++i) m_attributeNames.append(m_attributes.at(i).constData()); m_attributeNames.append(0); } diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h index 31e503be42..94bb315566 100644 --- a/src/quick/items/qquickshadereffectsource_p.h +++ b/src/quick/items/qquickshadereffectsource_p.h @@ -67,7 +67,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged) Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) - Q_ENUMS(Format WrapMode) public: enum WrapMode { ClampToEdge, @@ -75,12 +74,14 @@ public: RepeatVertically, Repeat }; + Q_ENUM(WrapMode) enum Format { Alpha = GL_ALPHA, RGB = GL_RGB, RGBA = GL_RGBA }; + Q_ENUM(Format) QQuickShaderEffectSource(QQuickItem *parent = 0); ~QQuickShaderEffectSource(); diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index 579919db27..ac7fbc24af 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -358,7 +358,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction xa; xa.property = property; - xa.toBinding = QQmlAbstractBinding::getPointer(newBinding); + xa.toBinding = newBinding; xa.fromValue = xa.property.read(); xa.deletableToBinding = true; actions << xa; @@ -377,7 +377,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction ya; ya.property = property; - ya.toBinding = QQmlAbstractBinding::getPointer(newBinding); + ya.toBinding = newBinding; ya.fromValue = ya.property.read(); ya.deletableToBinding = true; actions << ya; @@ -396,7 +396,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction sa; sa.property = property; - sa.toBinding = QQmlAbstractBinding::getPointer(newBinding); + sa.toBinding = newBinding; sa.fromValue = sa.property.read(); sa.deletableToBinding = true; actions << sa; @@ -415,7 +415,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction ra; ra.property = property; - ra.toBinding = QQmlAbstractBinding::getPointer(newBinding); + ra.toBinding = newBinding; ra.fromValue = ra.property.read(); ra.deletableToBinding = true; actions << ra; @@ -434,7 +434,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction wa; wa.property = property; - wa.toBinding = QQmlAbstractBinding::getPointer(newBinding); + wa.toBinding = newBinding; wa.fromValue = wa.property.read(); wa.deletableToBinding = true; actions << wa; @@ -453,7 +453,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction ha; ha.property = property; - ha.toBinding = QQmlAbstractBinding::getPointer(newBinding); + ha.toBinding = newBinding; ha.fromValue = ha.property.read(); ha.deletableToBinding = true; actions << ha; @@ -482,7 +482,7 @@ void QQuickParentChange::saveOriginals() saveCurrentValues(); }*/ -void QQuickParentChange::execute(Reason) +void QQuickParentChange::execute() { Q_D(QQuickParentChange); d->doChange(d->parent); @@ -493,7 +493,7 @@ bool QQuickParentChange::isReversable() return true; } -void QQuickParentChange::reverse(Reason) +void QQuickParentChange::reverse() { Q_D(QQuickParentChange); d->doChange(d->origParent, d->origStackBefore); @@ -765,12 +765,7 @@ class QQuickAnchorChangesPrivate : public QQuickStateOperationPrivate { public: QQuickAnchorChangesPrivate() - : target(0), anchorSet(new QQuickAnchorSet), - leftBinding(0), rightBinding(0), hCenterBinding(0), - topBinding(0), bottomBinding(0), vCenterBinding(0), baselineBinding(0), - origLeftBinding(0), origRightBinding(0), origHCenterBinding(0), - origTopBinding(0), origBottomBinding(0), origVCenterBinding(0), - origBaselineBinding(0) + : target(0), anchorSet(new QQuickAnchorSet) { } @@ -779,21 +774,21 @@ public: QQuickItem *target; QQuickAnchorSet *anchorSet; - QQmlBinding *leftBinding; - QQmlBinding *rightBinding; - QQmlBinding *hCenterBinding; - QQmlBinding *topBinding; - QQmlBinding *bottomBinding; - QQmlBinding *vCenterBinding; - QQmlBinding *baselineBinding; - - QQmlAbstractBinding *origLeftBinding; - QQmlAbstractBinding *origRightBinding; - QQmlAbstractBinding *origHCenterBinding; - QQmlAbstractBinding *origTopBinding; - QQmlAbstractBinding *origBottomBinding; - QQmlAbstractBinding *origVCenterBinding; - QQmlAbstractBinding *origBaselineBinding; + QExplicitlySharedDataPointer<QQmlBinding> leftBinding; + QExplicitlySharedDataPointer<QQmlBinding> rightBinding; + QExplicitlySharedDataPointer<QQmlBinding> hCenterBinding; + QExplicitlySharedDataPointer<QQmlBinding> topBinding; + QExplicitlySharedDataPointer<QQmlBinding> bottomBinding; + QExplicitlySharedDataPointer<QQmlBinding> vCenterBinding; + QExplicitlySharedDataPointer<QQmlBinding> baselineBinding; + + QQmlAbstractBinding::Ptr origLeftBinding; + QQmlAbstractBinding::Ptr origRightBinding; + QQmlAbstractBinding::Ptr origHCenterBinding; + QQmlAbstractBinding::Ptr origTopBinding; + QQmlAbstractBinding::Ptr origBottomBinding; + QQmlAbstractBinding::Ptr origVCenterBinding; + QQmlAbstractBinding::Ptr origBaselineBinding; QQuickAnchorLine rewindLeft; QQuickAnchorLine rewindRight; @@ -831,8 +826,6 @@ public: qreal origX; qreal origY; - QList<QQmlAbstractBinding*> oldBindings; - QQmlProperty leftProp; QQmlProperty rightProp; QQmlProperty hCenterProp; @@ -849,29 +842,6 @@ QQuickAnchorChanges::QQuickAnchorChanges(QObject *parent) QQuickAnchorChanges::~QQuickAnchorChanges() { - /* - if the anchorchanges is active at destruction, any non-active orig - bindings need to be destroyed - - the basic logic is that if both e.g. left and origLeft are present, - then we are active (otherwise left would have been destroyed), and - left is in use and origLeft needs to be cleaned up. - */ - Q_D(QQuickAnchorChanges); - if (d->leftBinding && d->origLeftBinding) - d->origLeftBinding->destroy(); - if (d->rightBinding && d->origRightBinding) - d->origRightBinding->destroy(); - if (d->hCenterBinding && d->origHCenterBinding) - d->origHCenterBinding->destroy(); - if (d->topBinding && d->origTopBinding) - d->origTopBinding->destroy(); - if (d->bottomBinding && d->origBottomBinding) - d->origBottomBinding->destroy(); - if (d->vCenterBinding && d->origVCenterBinding) - d->origVCenterBinding->destroy(); - if (d->baselineBinding && d->origBaselineBinding) - d->origBaselineBinding->destroy(); } QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions() @@ -967,7 +937,7 @@ void QQuickAnchorChanges::setObject(QQuickItem *target) \endqml */ -void QQuickAnchorChanges::execute(Reason reason) +void QQuickAnchorChanges::execute() { Q_D(QQuickAnchorChanges); if (!d->target) @@ -978,94 +948,84 @@ void QQuickAnchorChanges::execute(Reason reason) if (d->applyOrigLeft) { if (!d->origLeftBinding) targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding); + QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding.data()); } if (d->applyOrigRight) { if (!d->origRightBinding) targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding); + QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding.data()); } if (d->applyOrigHCenter) { if (!d->origHCenterBinding) targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding); + QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding.data()); } if (d->applyOrigTop) { if (!d->origTopBinding) targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding); + QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding.data()); } if (d->applyOrigBottom) { if (!d->origBottomBinding) targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding); + QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding.data()); } if (d->applyOrigVCenter) { if (!d->origVCenterBinding) targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding); + QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding.data()); } if (d->applyOrigBaseline) { if (!d->origBaselineBinding) targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding); - } - - //destroy old bindings - if (reason == ActualChange) { - for (int i = 0; i < d->oldBindings.size(); ++i) { - QQmlAbstractBinding *binding = d->oldBindings.at(i); - if (binding) - binding->destroy(); - } - d->oldBindings.clear(); + QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding.data()); } //reset any anchors that have been specified as "undefined" if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::LeftAnchor) { targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftProp, 0); + QQmlPropertyPrivate::removeBinding(d->leftProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::RightAnchor) { targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightProp, 0); + QQmlPropertyPrivate::removeBinding(d->rightProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::HCenterAnchor) { targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->hCenterProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::TopAnchor) { targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topProp, 0); + QQmlPropertyPrivate::removeBinding(d->topProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::BottomAnchor) { targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomProp, 0); + QQmlPropertyPrivate::removeBinding(d->bottomProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::VCenterAnchor) { targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->vCenterProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::BaselineAnchor) { targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineProp, 0); + QQmlPropertyPrivate::removeBinding(d->baselineProp); } //set any anchors that have been specified if (d->leftBinding) - QQmlPropertyPrivate::setBinding(d->leftBinding->property(), d->leftBinding); + QQmlPropertyPrivate::setBinding(d->leftBinding.data()); if (d->rightBinding) - QQmlPropertyPrivate::setBinding(d->rightBinding->property(), d->rightBinding); + QQmlPropertyPrivate::setBinding(d->rightBinding.data()); if (d->hCenterBinding) - QQmlPropertyPrivate::setBinding(d->hCenterBinding->property(), d->hCenterBinding); + QQmlPropertyPrivate::setBinding(d->hCenterBinding.data()); if (d->topBinding) - QQmlPropertyPrivate::setBinding(d->topBinding->property(), d->topBinding); + QQmlPropertyPrivate::setBinding(d->topBinding.data()); if (d->bottomBinding) - QQmlPropertyPrivate::setBinding(d->bottomBinding->property(), d->bottomBinding); + QQmlPropertyPrivate::setBinding(d->bottomBinding.data()); if (d->vCenterBinding) - QQmlPropertyPrivate::setBinding(d->vCenterBinding->property(), d->vCenterBinding); + QQmlPropertyPrivate::setBinding(d->vCenterBinding.data()); if (d->baselineBinding) - QQmlPropertyPrivate::setBinding(d->baselineBinding->property(), d->baselineBinding); + QQmlPropertyPrivate::setBinding(d->baselineBinding.data()); } bool QQuickAnchorChanges::isReversable() @@ -1073,7 +1033,7 @@ bool QQuickAnchorChanges::isReversable() return true; } -void QQuickAnchorChanges::reverse(Reason reason) +void QQuickAnchorChanges::reverse() { Q_D(QQuickAnchorChanges); if (!d->target) @@ -1083,69 +1043,48 @@ void QQuickAnchorChanges::reverse(Reason reason) //reset any anchors set by the state if (d->leftBinding) { targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftBinding->property(), 0); - if (reason == ActualChange) { - d->leftBinding->destroy(); d->leftBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->leftBinding.data()); } if (d->rightBinding) { targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightBinding->property(), 0); - if (reason == ActualChange) { - d->rightBinding->destroy(); d->rightBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->rightBinding.data()); } if (d->hCenterBinding) { targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterBinding->property(), 0); - if (reason == ActualChange) { - d->hCenterBinding->destroy(); d->hCenterBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->hCenterBinding.data()); } if (d->topBinding) { targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topBinding->property(), 0); - if (reason == ActualChange) { - d->topBinding->destroy(); d->topBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->topBinding.data()); } if (d->bottomBinding) { targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomBinding->property(), 0); - if (reason == ActualChange) { - d->bottomBinding->destroy(); d->bottomBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->bottomBinding.data()); } if (d->vCenterBinding) { targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterBinding->property(), 0); - if (reason == ActualChange) { - d->vCenterBinding->destroy(); d->vCenterBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->vCenterBinding.data()); } if (d->baselineBinding) { targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineBinding->property(), 0); - if (reason == ActualChange) { - d->baselineBinding->destroy(); d->baselineBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->baselineBinding.data()); } //restore previous anchors if (d->origLeftBinding) - QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding); + QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding.data()); if (d->origRightBinding) - QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding); + QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding.data()); if (d->origHCenterBinding) - QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding); + QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding.data()); if (d->origTopBinding) - QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding); + QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding.data()); if (d->origBottomBinding) - QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding); + QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding.data()); if (d->origVCenterBinding) - QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding); + QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding.data()); if (d->origBaselineBinding) - QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding); + QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding.data()); //restore any absolute geometry changed by the state's anchors QQuickAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Vertical_Mask; @@ -1289,10 +1228,6 @@ void QQuickAnchorChanges::copyOriginals(QQuickStateActionEvent *other) d->origX = acp->origX; d->origY = acp->origY; - d->oldBindings.clear(); - d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding - << acp->topBinding << acp->bottomBinding << acp->vCenterBinding << acp->baselineBinding; - //clear old values from other //### could this be generalized for all QQuickStateActionEvents, and called after copyOriginals? acp->leftBinding = 0; @@ -1333,31 +1268,31 @@ void QQuickAnchorChanges::clearBindings() d->anchorSet->d_func()->usedAnchors; if (d->applyOrigLeft || (combined & QQuickAnchors::LeftAnchor)) { targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftProp, 0); + QQmlPropertyPrivate::removeBinding(d->leftProp); } if (d->applyOrigRight || (combined & QQuickAnchors::RightAnchor)) { targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightProp, 0); + QQmlPropertyPrivate::removeBinding(d->rightProp); } if (d->applyOrigHCenter || (combined & QQuickAnchors::HCenterAnchor)) { targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->hCenterProp); } if (d->applyOrigTop || (combined & QQuickAnchors::TopAnchor)) { targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topProp, 0); + QQmlPropertyPrivate::removeBinding(d->topProp); } if (d->applyOrigBottom || (combined & QQuickAnchors::BottomAnchor)) { targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomProp, 0); + QQmlPropertyPrivate::removeBinding(d->bottomProp); } if (d->applyOrigVCenter || (combined & QQuickAnchors::VCenterAnchor)) { targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->vCenterProp); } if (d->applyOrigBaseline || (combined & QQuickAnchors::BaselineAnchor)) { targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineProp, 0); + QQmlPropertyPrivate::removeBinding(d->baselineProp); } } diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h index 8d4231c5fa..1999e23a83 100644 --- a/src/quick/items/qquickstateoperations_p.h +++ b/src/quick/items/qquickstateoperations_p.h @@ -97,9 +97,9 @@ public: void saveOriginals() Q_DECL_OVERRIDE; //virtual void copyOriginals(QQuickStateActionEvent*); - void execute(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void execute() Q_DECL_OVERRIDE; bool isReversable() Q_DECL_OVERRIDE; - void reverse(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void reverse() Q_DECL_OVERRIDE; EventType type() const Q_DECL_OVERRIDE; bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE; void rewind() Q_DECL_OVERRIDE; @@ -180,9 +180,9 @@ public: QQuickItem *object() const; void setObject(QQuickItem *); - void execute(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void execute() Q_DECL_OVERRIDE; bool isReversable() Q_DECL_OVERRIDE; - void reverse(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void reverse() Q_DECL_OVERRIDE; EventType type() const Q_DECL_OVERRIDE; bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE; bool changesBindings() Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index dd4f57bfdb..2475d19c8d 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -85,7 +85,16 @@ QQuickTextPrivate::QQuickTextPrivate() } QQuickTextPrivate::ExtraData::ExtraData() - : lineHeight(1.0) + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) + , lineHeight(1.0) , doc(0) , minimumPixelSize(12) , minimumPointSize(12) @@ -283,6 +292,74 @@ qreal QQuickTextPrivate::getImplicitHeight() const return implicitHeight; } +qreal QQuickTextPrivate::availableWidth() const +{ + Q_Q(const QQuickText); + return q->width() - q->leftPadding() - q->rightPadding(); +} + +qreal QQuickTextPrivate::availableHeight() const +{ + Q_Q(const QQuickText); + return q->height() - q->topPadding() - q->bottomPadding(); +} + +void QQuickTextPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->topPaddingChanged(); + } +} + +void QQuickTextPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->leftPaddingChanged(); + } +} + +void QQuickTextPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->rightPaddingChanged(); + } +} + +void QQuickTextPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->bottomPaddingChanged(); + } +} + /*! \qmlproperty bool QtQuick::Text::antialiasing @@ -326,9 +403,9 @@ void QQuickTextPrivate::updateLayout() formatModifiesFontSize = fontSizeModified; multilengthEos = -1; } else { - layout.clearAdditionalFormats(); + layout.clearFormats(); if (elideLayout) - elideLayout->clearAdditionalFormats(); + elideLayout->clearFormats(); QString tmp = text; multilengthEos = tmp.indexOf(QLatin1Char('\x9c')); if (multilengthEos != -1) { @@ -409,7 +486,7 @@ void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy) yoff = dy/2; } - q->setBaselineOffset(baseline + yoff); + q->setBaselineOffset(baseline + yoff + q->topPadding()); } void QQuickTextPrivate::updateSize() @@ -429,6 +506,9 @@ void QQuickTextPrivate::updateSize() return; } + qreal hPadding = q->leftPadding() + q->rightPadding(); + qreal vPadding = q->topPadding() + q->bottomPadding(); + if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) { // How much more expensive is it to just do a full layout on an empty string here? // There may be subtle differences in the height and baseline calculations between @@ -441,8 +521,8 @@ void QQuickTextPrivate::updateSize() ? lineHeight() : fontHeight * lineHeight(); } - updateBaseline(fm.ascent(), q->height() - fontHeight); - q->setImplicitSize(0, fontHeight); + updateBaseline(fm.ascent(), q->height() - fontHeight - vPadding); + q->setImplicitSize(hPadding, fontHeight + vPadding); layedOutTextRect = QRectF(0, 0, 0, fontHeight); emit q->contentSizeChanged(); updateType = UpdatePaintNode; @@ -463,7 +543,7 @@ void QQuickTextPrivate::updateSize() layedOutTextRect = textRect; size = textRect.size(); - updateBaseline(baseline, q->height() - size.height()); + updateBaseline(baseline, q->height() - size.height() - vPadding); } else { widthExceeded = true; // always relayout rich text on width changes.. heightExceeded = false; // rich text layout isn't affected by height changes. @@ -487,15 +567,15 @@ void QQuickTextPrivate::updateSize() naturalWidth = extra->doc->idealWidth(); const bool wasInLayout = internalWidthUpdate; internalWidthUpdate = true; - q->setImplicitWidth(naturalWidth); + q->setImplicitWidth(naturalWidth + hPadding); internalWidthUpdate = wasInLayout; } if (internalWidthUpdate) return; extra->doc->setPageSize(QSizeF()); - if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < q->width())) - extra->doc->setTextWidth(q->width()); + if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth())) + extra->doc->setTextWidth(availableWidth()); else extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) @@ -504,7 +584,7 @@ void QQuickTextPrivate::updateSize() size = QSizeF(extra->doc->idealWidth(),dsize.height()); QFontMetricsF fm(font); - updateBaseline(fm.ascent(), q->height() - size.height()); + updateBaseline(fm.ascent(), q->height() - size.height() - vPadding); //### need to confirm cost of always setting these for richText internalWidthUpdate = true; @@ -512,11 +592,11 @@ void QQuickTextPrivate::updateSize() if (!q->widthValid()) iWidth = size.width(); if (iWidth > -1) - q->setImplicitSize(iWidth, size.height()); + q->setImplicitSize(iWidth + hPadding, size.height() + vPadding); internalWidthUpdate = false; if (iWidth == -1) - q->setImplicitHeight(size.height()); + q->setImplicitHeight(size.height() + vPadding); } if (layedOutTextRect.size() != previousSize) @@ -622,7 +702,7 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, // use the text item's width by default if it has one and wrap is on or text must be aligned if (q->widthValid() && (q->wrapMode() != QQuickText::NoWrap || q->effectiveHAlign() != QQuickText::AlignLeft)) - textLine->setWidth(q->width()); + textLine->setWidth(availableWidth()); else textLine->setWidth(INT_MAX); if (lineHeight() != 1.0) @@ -634,10 +714,10 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, } void QQuickTextPrivate::elideFormats( - const int start, const int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats) + const int start, const int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats) { const int end = start + length; - QList<QTextLayout::FormatRange> formats = layout.additionalFormats(); + const QVector<QTextLayout::FormatRange> formats = layout.formats(); for (int i = 0; i < formats.count(); ++i) { QTextLayout::FormatRange format = formats.at(i); const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start); @@ -690,10 +770,11 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) && (q->heightValid() || maximumLineCountValid); if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid)) - && ((singlelineElide && q->width() <= 0.) || (multilineElide && q->heightValid() && q->height() <= 0.))) { + && ((singlelineElide && availableWidth() <= 0.) + || (multilineElide && q->heightValid() && availableHeight() <= 0.))) { // we are elided and we have a zero width or height - widthExceeded = q->widthValid() && q->width() <= 0.; - heightExceeded = q->heightValid() && q->height() <= 0.; + widthExceeded = q->widthValid() && availableWidth() <= 0.; + heightExceeded = q->heightValid() && availableHeight() <= 0.; if (!truncated) { truncated = true; @@ -729,7 +810,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0 ? q->width() : FLT_MAX; - qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX; + qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX; const bool customLayout = isLineLaidOutConnected(); const bool wasTruncated = truncated; @@ -750,8 +831,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) int scaledFontSize = largeFont; bool widthChanged = false; - widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit); - heightExceeded = q->height() <= 0 && (multilineElide || verticalFit); + widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit); + heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit); QRectF br; @@ -921,7 +1002,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) bool wasInLayout = internalWidthUpdate; internalWidthUpdate = true; - q->setImplicitSize(naturalWidth, naturalHeight); + q->setImplicitSize(naturalWidth + q->leftPadding() + q->rightPadding(), naturalHeight + q->topPadding() + q->bottomPadding()); internalWidthUpdate = wasInLayout; // Update any variables that are dependent on the validity of the width or height. @@ -938,8 +1019,11 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) const qreal oldWidth = lineWidth; const qreal oldHeight = maxHeight; - lineWidth = q->widthValid() && q->width() > 0 ? q->width() : naturalWidth; - maxHeight = q->heightValid() ? q->height() : FLT_MAX; + const qreal availWidth = availableWidth(); + const qreal availHeight = availableHeight(); + + lineWidth = q->widthValid() && availWidth > 0 ? availWidth : naturalWidth; + maxHeight = q->heightValid() ? availHeight : FLT_MAX; // If the width of the item has changed and it's possible the result of wrapping, // eliding, scaling has changed, or the text is not left aligned do another layout. @@ -992,7 +1076,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) && (q->heightValid() || (maximumLineCountValid && canWrap)); const qreal oldHeight = maxHeight; - maxHeight = q->heightValid() ? q->height() : FLT_MAX; + maxHeight = q->heightValid() ? availableHeight() : FLT_MAX; // If the height of the item has changed and it's possible the result of eliding, // line count truncation or scaling has changed, do another layout. if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight)) @@ -1072,7 +1156,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) elideLayout->setCacheEnabled(true); } if (styledText) { - QList<QTextLayout::FormatRange> formats; + QVector<QTextLayout::FormatRange> formats; switch (elideMode) { case QQuickText::ElideRight: elideFormats(elideStart, elideText.length() - 1, 0, &formats); @@ -1095,7 +1179,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) default: break; } - elideLayout->setAdditionalFormats(formats); + elideLayout->setFormats(formats); } elideLayout->setFont(layout.font()); @@ -2278,7 +2362,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data d->updateType = QQuickTextPrivate::UpdateNone; - const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), height(), d->vAlign); + const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), d->availableHeight(), d->vAlign) + topPadding(); QQuickTextNode *node = 0; if (!oldNode) @@ -2295,11 +2379,11 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data const QColor linkColor = QColor::fromRgba(d->linkColor); if (d->richText) { - const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), effectiveHAlign()); + const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), d->availableWidth(), effectiveHAlign()) + leftPadding(); d->ensureDoc(); node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor); } else if (d->layedOutTextRect.width() > 0) { - const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), effectiveHAlign()); + const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, d->availableWidth(), effectiveHAlign()) + leftPadding(); int unelidedLineCount = d->lineCount; if (d->elideLayout) unelidedLineCount -= 1; @@ -2567,7 +2651,7 @@ QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mo QTextLine line = layout->lineAt(i); if (line.naturalTextRect().contains(mousePos)) { int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter); - foreach (const QTextLayout::FormatRange &formatRange, layout->additionalFormats()) { + foreach (const QTextLayout::FormatRange &formatRange, layout->formats()) { if (formatRange.format.isAnchor() && charPos >= formatRange.start && charPos < formatRange.start + formatRange.length) { @@ -2584,14 +2668,15 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const { Q_Q(const QQuickText); QPointF translatedMousePos = mousePos; - translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), q->height(), vAlign); + translatedMousePos.rx() -= q->leftPadding(); + translatedMousePos.ry() -= q->topPadding() + QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), availableHeight(), vAlign); if (styledText) { QString link = anchorAt(&layout, translatedMousePos); if (link.isEmpty() && elideLayout) link = anchorAt(elideLayout, translatedMousePos); return link; } else if (richText && extra.isAllocated() && extra->doc) { - translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), q->effectiveHAlign()); + translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), availableWidth(), q->effectiveHAlign()); return extra->doc->documentLayout()->anchorAt(translatedMousePos); } return QString(); @@ -2809,4 +2894,125 @@ void QQuickText::invalidateFontCaches() } } +/*! + \since 5.6 + \qmlproperty real QtQuick::Text::padding + \qmlproperty real QtQuick::Text::topPadding + \qmlproperty real QtQuick::Text::leftPadding + \qmlproperty real QtQuick::Text::bottomPadding + \qmlproperty real QtQuick::Text::rightPadding + + These properties hold the padding around the content. This space is reserved + in addition to the contentWidth and contentHeight. +*/ +qreal QQuickText::padding() const +{ + Q_D(const QQuickText); + return d->padding(); +} + +void QQuickText::setPadding(qreal padding) +{ + Q_D(QQuickText); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + d->updateSize(); + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickText::resetPadding() +{ + setPadding(0); +} + +qreal QQuickText::topPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickText::setTopPadding(qreal padding) +{ + Q_D(QQuickText); + d->setTopPadding(padding); +} + +void QQuickText::resetTopPadding() +{ + Q_D(QQuickText); + d->setTopPadding(0, true); +} + +qreal QQuickText::leftPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickText::setLeftPadding(qreal padding) +{ + Q_D(QQuickText); + d->setLeftPadding(padding); +} + +void QQuickText::resetLeftPadding() +{ + Q_D(QQuickText); + d->setLeftPadding(0, true); +} + +qreal QQuickText::rightPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickText::setRightPadding(qreal padding) +{ + Q_D(QQuickText); + d->setRightPadding(padding); +} + +void QQuickText::resetRightPadding() +{ + Q_D(QQuickText); + d->setRightPadding(0, true); +} + +qreal QQuickText::bottomPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickText::setBottomPadding(qreal padding) +{ + Q_D(QQuickText); + d->setBottomPadding(padding); +} + +void QQuickText::resetBottomPadding() +{ + Q_D(QQuickText); + d->setBottomPadding(0, true); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index 283e3b510b..f92927c9c4 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -45,15 +45,6 @@ class QQuickTextLine; class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) - Q_ENUMS(TextStyle) - Q_ENUMS(TextFormat) - Q_ENUMS(TextElideMode) - Q_ENUMS(WrapMode) - Q_ENUMS(LineHeightMode) - Q_ENUMS(FontSizeMode) - Q_ENUMS(RenderType) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) @@ -84,6 +75,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) + public: QQuickText(QQuickItem *parent=0); ~QQuickText(); @@ -92,21 +89,26 @@ public: AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter, AlignJustify = Qt::AlignJustify }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum TextStyle { Normal, Outline, Raised, Sunken }; + Q_ENUM(TextStyle) enum TextFormat { PlainText = Qt::PlainText, RichText = Qt::RichText, AutoText = Qt::AutoText, StyledText = 4 }; + Q_ENUM(TextFormat) enum TextElideMode { ElideLeft = Qt::ElideLeft, ElideRight = Qt::ElideRight, ElideMiddle = Qt::ElideMiddle, ElideNone = Qt::ElideNone }; + Q_ENUM(TextElideMode) enum WrapMode { NoWrap = QTextOption::NoWrap, WordWrap = QTextOption::WordWrap, @@ -114,15 +116,19 @@ public: WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + Q_ENUM(WrapMode) enum RenderType { QtRendering, NativeRendering }; + Q_ENUM(RenderType) enum LineHeightMode { ProportionalHeight, FixedHeight }; + Q_ENUM(LineHeightMode) enum FontSizeMode { FixedSize = 0x0, HorizontalFit = 0x01, VerticalFit = 0x02, Fit = HorizontalFit | VerticalFit }; + Q_ENUM(FontSizeMode) QString text() const; void setText(const QString &); @@ -204,6 +210,26 @@ public: Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + Q_SIGNALS: void textChanged(const QString &text); void linkActivated(const QString &link); @@ -231,6 +257,11 @@ Q_SIGNALS: void lineLaidOut(QQuickTextLine *line); void baseUrlChanged(); void renderTypeChanged(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index 9a6da3736e..f0469fc8ea 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -78,7 +78,7 @@ public: int lineHeightOffset() const; QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; - void elideFormats(int start, int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats); + void elideFormats(int start, int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats); void processHoverEvent(QHoverEvent *event); @@ -87,6 +87,15 @@ public: struct ExtraData { ExtraData(); + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; qreal lineHeight; QQuickTextDocumentWithImageResources *doc; QString activeLink; @@ -159,6 +168,15 @@ public: qreal getImplicitWidth() const Q_DECL_OVERRIDE; qreal getImplicitHeight() const Q_DECL_OVERRIDE; + qreal availableWidth() const; + qreal availableHeight() const; + + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + void ensureDoc(); QRectF setupTextLayout(qreal * const baseline); diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 95d2e7c995..19cdc388f1 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -1313,7 +1313,7 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) QTextLayout *layout = block.layout(); if (isGettingInput) layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); - QList<QTextLayout::FormatRange> overrides; + QVector<QTextLayout::FormatRange> overrides; const int oldPreeditCursor = preeditCursor; preeditCursor = e->preeditString().length(); hasImState = !e->preeditString().isEmpty(); @@ -1336,7 +1336,7 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } } } - layout->setAdditionalFormats(overrides); + layout->setFormats(overrides); cursor.endEditBlock(); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 8237ad10e4..2887dad8ce 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -172,6 +172,13 @@ QQuickTextEdit::QQuickTextEdit(QQuickItem *parent) d->init(); } +QQuickTextEdit::QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent) +: QQuickImplicitSizeItem(dd, parent) +{ + Q_D(QQuickTextEdit); + d->init(); +} + QString QQuickTextEdit::text() const { Q_D(const QQuickTextEdit); @@ -699,6 +706,62 @@ Qt::InputMethodHints QQuickTextEditPrivate::effectiveInputMethodHints() const } #endif +void QQuickTextEditPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->topPaddingChanged(); + } +} + +void QQuickTextEditPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->leftPaddingChanged(); + } +} + +void QQuickTextEditPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->rightPaddingChanged(); + } +} + +void QQuickTextEditPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->bottomPaddingChanged(); + } +} + QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const { Q_D(const QQuickTextEdit); @@ -1658,6 +1721,8 @@ void QQuickTextEdit::mousePressEvent(QMouseEvent *event) #ifndef QT_NO_IM if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) qGuiApp->inputMethod()->show(); +#else + Q_UNUSED(hadActiveFocus); #endif } if (!event->isAccepted()) @@ -1793,6 +1858,14 @@ void QQuickTextEdit::invalidateFontCaches() } } +inline void resetEngine(QQuickTextNodeEngine *engine, const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor) +{ + *engine = QQuickTextNodeEngine(); + engine->setTextColor(textColor); + engine->setSelectedTextColor(selectedTextColor); + engine->setSelectionColor(selectionColor); +} + QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) { Q_UNUSED(updatePaintNodeData); @@ -1818,6 +1891,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * while (nodeIterator != d->textNodeMap.end() && !(*nodeIterator)->dirty()) ++nodeIterator; + QQuickTextNodeEngine engine; + QQuickTextNodeEngine frameDecorationsEngine; if (!oldNode || nodeIterator < d->textNodeMap.end()) { @@ -1837,6 +1912,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * // FIXME: the text decorations could probably be handled separately (only updated for affected textFrames) rootNode->resetFrameDecorations(d->createTextNode()); + resetEngine(&frameDecorationsEngine, d->color, d->selectedTextColor, d->selectionColor); QQuickTextNode *node = 0; @@ -1856,11 +1932,12 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * while (!frames.isEmpty()) { QTextFrame *textFrame = frames.takeFirst(); frames.append(textFrame->childFrames()); - rootNode->frameDecorationsNode->m_engine->addFrameDecorations(d->document, textFrame); + frameDecorationsEngine.addFrameDecorations(d->document, textFrame); if (textFrame->lastPosition() < firstDirtyPos || (firstCleanNode && textFrame->firstPosition() >= firstCleanNode->startPos())) continue; node = d->createTextNode(); + resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor); if (textFrame->firstPosition() > textFrame->lastPosition() && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) { @@ -1869,8 +1946,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout()); QTextCharFormat format = a->formatAccessor(pos); QTextBlock block = textFrame->firstCursorPosition().block(); - node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, + engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); + engine.addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, pos, textFrame->frameFormat().position()); nodeStart = pos; } else if (qobject_cast<QTextTable*>(textFrame)) { // To keep things simple, map text tables as one text node @@ -1878,7 +1955,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * nodeOffset = d->document->documentLayout()->frameBoundingRect(textFrame).topLeft(); updateNodeTransform(node, nodeOffset); while (!it.atEnd()) - node->m_engine->addTextBlock(d->document, (it++).currentBlock(), -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); + engine.addTextBlock(d->document, (it++).currentBlock(), -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); nodeStart = textFrame->firstPosition(); } else { // Having nodes spanning across frame boundaries will break the current bookkeeping mechanism. We need to prevent that. @@ -1895,13 +1972,13 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * if (block.position() < firstDirtyPos) continue; - if (!node->m_engine->hasContents()) { + if (!engine.hasContents()) { nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft(); updateNodeTransform(node, nodeOffset); nodeStart = block.position(); } - node->m_engine->addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); + engine.addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); currentNodeSize += block.length(); if ((it.atEnd()) || (firstCleanNode && block.next().position() >= firstCleanNode->startPos())) // last node that needed replacing or last block of the frame @@ -1910,15 +1987,16 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * QList<int>::const_iterator lowerBound = std::lower_bound(frameBoundaries.constBegin(), frameBoundaries.constEnd(), block.next().position()); if (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart) { currentNodeSize = 0; - d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart); + d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart); node = d->createTextNode(); + resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor); nodeStart = block.next().position(); } } } - d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart); + d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart); } - rootNode->frameDecorationsNode->m_engine->addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor()); + frameDecorationsEngine.addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor()); // Now prepend the frame decorations since we want them rendered first, with the text nodes and cursor in front. rootNode->prependChildNode(rootNode->frameDecorationsNode); @@ -2023,6 +2101,19 @@ bool QQuickTextEdit::isInputMethodComposing() const #endif // QT_NO_IM } +QQuickTextEditPrivate::ExtraData::ExtraData() + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) +{ +} + void QQuickTextEditPrivate::init() { Q_Q(QQuickTextEdit); @@ -2106,7 +2197,7 @@ void QQuickTextEdit::markDirtyNodesForRange(int start, int end, int charDelta) } // mark the affected nodes as dirty - while (it != d->textNodeMap.constEnd()) { + while (it != d->textNodeMap.end()) { if ((*it)->startPos() <= end) (*it)->setDirty(); else if (charDelta) @@ -2232,7 +2323,7 @@ void QQuickTextEdit::updateSize() return; } - qreal naturalWidth = d->implicitWidth; + qreal naturalWidth = d->implicitWidth - leftPadding() - rightPadding(); qreal newWidth = d->document->idealWidth(); // ### assumes that if the width is set, the text will fill to edges @@ -2250,13 +2341,13 @@ void QQuickTextEdit::updateSize() const bool wasInLayout = d->inLayout; d->inLayout = true; - setImplicitWidth(naturalWidth); + setImplicitWidth(naturalWidth + leftPadding() + rightPadding()); d->inLayout = wasInLayout; if (d->inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. } if (d->document->textWidth() != width()) { - d->document->setTextWidth(width()); + d->document->setTextWidth(width() - leftPadding() - rightPadding()); newWidth = d->document->idealWidth(); } //### need to confirm cost of always setting these @@ -2271,12 +2362,12 @@ void QQuickTextEdit::updateSize() // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. if (!widthValid() && !d->requireImplicitWidth) - setImplicitSize(newWidth, newHeight); + setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding()); else - setImplicitHeight(newHeight); + setImplicitHeight(newHeight + topPadding() + bottomPadding()); - d->xoff = qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign())); - d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign); + d->xoff = leftPadding() + qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width() - leftPadding() - rightPadding(), effectiveHAlign())); + d->yoff = topPadding() + QQuickTextUtil::alignedY(d->document->size().height(), height() - topPadding() - bottomPadding(), d->vAlign); setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); QSizeF size(newWidth, newHeight); @@ -2423,16 +2514,19 @@ void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event) qGuiApp->inputMethod()->show(); q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)), q, SLOT(q_updateAlignment())); +#endif } else { +#ifndef QT_NO_IM q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)), q, SLOT(q_updateAlignment())); #endif + emit q->editingFinished(); } } -void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos) +void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QQuickTextNodeEngine *engine, QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos) { - node->m_engine->addToSceneGraph(node, QQuickText::Normal, QColor()); + engine->addToSceneGraph(node, QQuickText::Normal, QColor()); it = textNodeMap.insert(it, new TextNode(startPos, node)); ++it; root->appendChildNode(node); @@ -2443,7 +2537,6 @@ QQuickTextNode *QQuickTextEditPrivate::createTextNode() Q_Q(QQuickTextEdit); QQuickTextNode* node = new QQuickTextNode(q); node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering); - node->initEngine(color, selectedTextColor, selectionColor); return node; } @@ -2595,6 +2688,15 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected() */ /*! + \qmlsignal QtQuick::TextEdit::editingFinished() + \since 5.6 + + This signal is emitted when the text edit loses focus. + + The corresponding handler is \c onEditingFinished. +*/ + +/*! \qmlproperty string QtQuick::TextEdit::hoveredLink \since 5.2 @@ -2687,7 +2789,132 @@ void QQuickTextEdit::append(const QString &text) QString QQuickTextEdit::linkAt(qreal x, qreal y) const { Q_D(const QQuickTextEdit); - return d->control->anchorAt(QPointF(x, y)); + return d->control->anchorAt(QPointF(x + topPadding(), y + leftPadding())); +} + +/*! + \since 5.6 + \qmlproperty real QtQuick::TextEdit::padding + \qmlproperty real QtQuick::TextEdit::topPadding + \qmlproperty real QtQuick::TextEdit::leftPadding + \qmlproperty real QtQuick::TextEdit::bottomPadding + \qmlproperty real QtQuick::TextEdit::rightPadding + + These properties hold the padding around the content. This space is reserved + in addition to the contentWidth and contentHeight. +*/ +qreal QQuickTextEdit::padding() const +{ + Q_D(const QQuickTextEdit); + return d->padding(); +} + +void QQuickTextEdit::setPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + updateSize(); + if (isComponentComplete()) { + d->updateType = QQuickTextEditPrivate::UpdatePaintNode; + update(); + } + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickTextEdit::resetPadding() +{ + setPadding(0); +} + +qreal QQuickTextEdit::topPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickTextEdit::setTopPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setTopPadding(padding); +} + +void QQuickTextEdit::resetTopPadding() +{ + Q_D(QQuickTextEdit); + d->setTopPadding(0, true); +} + +qreal QQuickTextEdit::leftPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickTextEdit::setLeftPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setLeftPadding(padding); +} + +void QQuickTextEdit::resetLeftPadding() +{ + Q_D(QQuickTextEdit); + d->setLeftPadding(0, true); +} + +qreal QQuickTextEdit::rightPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickTextEdit::setRightPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setRightPadding(padding); +} + +void QQuickTextEdit::resetRightPadding() +{ + Q_D(QQuickTextEdit); + d->setRightPadding(0, true); +} + +qreal QQuickTextEdit::bottomPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickTextEdit::setBottomPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setBottomPadding(padding); +} + +void QQuickTextEdit::resetBottomPadding() +{ + Q_D(QQuickTextEdit); + d->setBottomPadding(0, true); } QT_END_NAMESPACE diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index bf6763f772..cfe599c0d3 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -47,12 +47,6 @@ class QTextBlock; class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(VAlignment) - Q_ENUMS(HAlignment) - Q_ENUMS(TextFormat) - Q_ENUMS(WrapMode) - Q_ENUMS(SelectionMode) - Q_ENUMS(RenderType) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) @@ -91,8 +85,13 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged) Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl RESET resetBaseUrl NOTIFY baseUrlChanged) Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) - Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument FINAL REVISION 1) + Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument CONSTANT FINAL REVISION 1) Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) public: QQuickTextEdit(QQuickItem *parent=0); @@ -103,18 +102,21 @@ public: AlignHCenter = Qt::AlignHCenter, AlignJustify = Qt::AlignJustify }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum TextFormat { PlainText = Qt::PlainText, RichText = Qt::RichText, AutoText = Qt::AutoText }; + Q_ENUM(TextFormat) enum WrapMode { NoWrap = QTextOption::NoWrap, WordWrap = QTextOption::WordWrap, @@ -122,15 +124,18 @@ public: WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + Q_ENUM(WrapMode) enum SelectionMode { SelectCharacters, SelectWords }; + Q_ENUM(SelectionMode) enum RenderType { QtRendering, NativeRendering }; + Q_ENUM(RenderType) QString text() const; void setText(const QString &); @@ -247,6 +252,26 @@ public: Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + Q_SIGNALS: void textChanged(); void contentSizeChanged(); @@ -283,6 +308,12 @@ Q_SIGNALS: void baseUrlChanged(); void inputMethodHintsChanged(); void renderTypeChanged(); + Q_REVISION(6) void editingFinished(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); public Q_SLOTS: void selectAll(); @@ -321,6 +352,8 @@ private: void invalidateFontCaches(); protected: + QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent = 0); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index 0cf0f46532..a763f9e56e 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -47,18 +47,19 @@ #include "qquicktextedit_p.h" #include "qquickimplicitsizeitem_p_p.h" -#include "qquicktextcontrol_p.h" #include <QtQml/qqml.h> #include <QtCore/qlist.h> +#include <private/qlazilyallocated_p.h> QT_BEGIN_NAMESPACE class QTextLayout; class QQuickTextDocumentWithImageResources; class QQuickTextControl; class QQuickTextNode; +class QQuickTextNodeEngine; -class QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate { public: Q_DECLARE_PUBLIC(QQuickTextEdit) @@ -81,10 +82,26 @@ public: }; typedef QList<Node*>::iterator TextNodeIterator; + struct ExtraData { + ExtraData(); + + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; + }; + QLazilyAllocated<ExtraData> extra; + QQuickTextEditPrivate() : color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF)) - , textMargin(0.0), xoff(0), yoff(0), font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0) + , textMargin(0.0), xoff(0), yoff(0) + , font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0) , quickDocument(0), lastSelectionStart(0), lastSelectionEnd(0), lineCount(0) , hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop) , format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap) @@ -124,13 +141,19 @@ public: void setNativeCursorEnabled(bool) {} void handleFocusEvent(QFocusEvent *event); - void addCurrentTextNodeToRoot(QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos); + void addCurrentTextNodeToRoot(QQuickTextNodeEngine *, QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos); QQuickTextNode* createTextNode(); #ifndef QT_NO_IM Qt::InputMethodHints effectiveInputMethodHints() const; #endif + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + QColor color; QColor selectionColor; QColor selectedTextColor; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index a4c61209f2..b458f80ce7 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -90,6 +90,13 @@ QQuickTextInput::QQuickTextInput(QQuickItem* parent) d->init(); } +QQuickTextInput::QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent) +: QQuickImplicitSizeItem(dd, parent) +{ + Q_D(QQuickTextInput); + d->init(); +} + QQuickTextInput::~QQuickTextInput() { } @@ -786,8 +793,8 @@ QRectF QQuickTextInput::cursorRectangle() const QTextLine l = d->m_textLayout.lineForTextPosition(c); if (!l.isValid()) return QRectF(); - qreal x = l.cursorToX(c) - d->hscroll; - qreal y = l.y() - d->vscroll; + qreal x = l.cursorToX(c) - d->hscroll + leftPadding(); + qreal y = l.y() - d->vscroll + topPadding(); return QRectF(x, y, 1, l.height()); } @@ -910,189 +917,6 @@ void QQuickTextInput::setAutoScroll(bool b) emit autoScrollChanged(d->autoScroll); } -#ifndef QT_NO_VALIDATOR - -/*! - \qmltype IntValidator - \instantiates QIntValidator - \inqmlmodule QtQuick - \ingroup qtquick-text-utility - \brief Defines a validator for integer values - - The IntValidator type provides a validator for integer values. - - If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to - interpret the number and will accept locale specific digits, group separators, and positive - and negative signs. In addition, IntValidator is always guaranteed to accept a number - formatted according to the "C" locale. -*/ - - -QQuickIntValidator::QQuickIntValidator(QObject *parent) - : QIntValidator(parent) -{ -} - -/*! - \qmlproperty string QtQuick::IntValidator::locale - - This property holds the name of the locale used to interpret the number. - - \sa {QtQml::Qt::locale()}{Qt.locale()} -*/ - -QString QQuickIntValidator::localeName() const -{ - return locale().name(); -} - -void QQuickIntValidator::setLocaleName(const QString &name) -{ - if (locale().name() != name) { - setLocale(QLocale(name)); - emit localeNameChanged(); - } -} - -void QQuickIntValidator::resetLocaleName() -{ - QLocale defaultLocale; - if (locale() != defaultLocale) { - setLocale(defaultLocale); - emit localeNameChanged(); - } -} - -/*! - \qmlproperty int QtQuick::IntValidator::top - - This property holds the validator's highest acceptable value. - By default, this property's value is derived from the highest signed integer available (typically 2147483647). -*/ -/*! - \qmlproperty int QtQuick::IntValidator::bottom - - This property holds the validator's lowest acceptable value. - By default, this property's value is derived from the lowest signed integer available (typically -2147483647). -*/ - -/*! - \qmltype DoubleValidator - \instantiates QDoubleValidator - \inqmlmodule QtQuick - \ingroup qtquick-text-utility - \brief Defines a validator for non-integer numbers - - The DoubleValidator type provides a validator for non-integer numbers. - - Input is accepted if it contains a double that is within the valid range - and is in the correct format. - - Input is accepected but invalid if it contains a double that is outside - the range or is in the wrong format; e.g. with too many digits after the - decimal point or is empty. - - Input is rejected if it is not a double. - - Note: If the valid range consists of just positive doubles (e.g. 0.0 to - 100.0) and input is a negative double then it is rejected. If \l notation - is set to DoubleValidator.StandardNotation, and the input contains more - digits before the decimal point than a double in the valid range may have, - it is also rejected. If \l notation is DoubleValidator.ScientificNotation, - and the input is not in the valid range, it is accecpted but invalid. The - value may yet become valid by changing the exponent. -*/ - -QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent) - : QDoubleValidator(parent) -{ -} - -/*! - \qmlproperty string QtQuick::DoubleValidator::locale - - This property holds the name of the locale used to interpret the number. - - \sa {QtQml::Qt::locale()}{Qt.locale()} -*/ - -QString QQuickDoubleValidator::localeName() const -{ - return locale().name(); -} - -void QQuickDoubleValidator::setLocaleName(const QString &name) -{ - if (locale().name() != name) { - setLocale(QLocale(name)); - emit localeNameChanged(); - } -} - -void QQuickDoubleValidator::resetLocaleName() -{ - QLocale defaultLocale; - if (locale() != defaultLocale) { - setLocale(defaultLocale); - emit localeNameChanged(); - } -} - -#endif // QT_NO_VALIDATOR - -/*! - \qmlproperty real QtQuick::DoubleValidator::top - - This property holds the validator's maximum acceptable value. - By default, this property contains a value of infinity. -*/ -/*! - \qmlproperty real QtQuick::DoubleValidator::bottom - - This property holds the validator's minimum acceptable value. - By default, this property contains a value of -infinity. -*/ -/*! - \qmlproperty int QtQuick::DoubleValidator::decimals - - This property holds the validator's maximum number of digits after the decimal point. - By default, this property contains a value of 1000. -*/ -/*! - \qmlproperty enumeration QtQuick::DoubleValidator::notation - This property holds the notation of how a string can describe a number. - - The possible values for this property are: - - \list - \li DoubleValidator.StandardNotation - \li DoubleValidator.ScientificNotation (default) - \endlist - - If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2). -*/ - -/*! - \qmltype RegExpValidator - \instantiates QRegExpValidator - \inqmlmodule QtQuick - \ingroup qtquick-text-utility - \brief Provides a string validator - - The RegExpValidator type provides a validator, which counts as valid any string which - matches a specified regular expression. -*/ -/*! - \qmlproperty regExp QtQuick::RegExpValidator::regExp - - This property holds the regular expression used for validation. - - Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression - matching "a". - - By default, this property contains a regular expression with the pattern .* that matches any string. -*/ - /*! \qmlproperty Validator QtQuick::TextInput::validator @@ -1489,8 +1313,9 @@ void QQuickTextInput::positionAt(QQmlV4Function *args) const int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const { - x += hscroll; - y += vscroll; + Q_Q(const QQuickTextInput); + x += hscroll - q->leftPadding(); + y += vscroll - q->topPadding(); QTextLine line = m_textLayout.lineAt(0); for (int i = 1; i < m_textLayout.lineCount(); ++i) { QTextLine nextLine = m_textLayout.lineAt(i); @@ -1748,7 +1573,7 @@ void QQuickTextInputPrivate::ensureVisible(int position, int preeditCursor, int { Q_Q(QQuickTextInput); QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor); - const qreal width = qMax<qreal>(0, q->width()); + const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding()); qreal cix = 0; qreal widthUsed = 0; if (textLine.isValid()) { @@ -1811,7 +1636,7 @@ void QQuickTextInputPrivate::updateVerticalScroll() #ifndef QT_NO_IM const int preeditLength = m_textLayout.preeditAreaText().length(); #endif - const qreal height = qMax<qreal>(0, q->height()); + const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding()); qreal heightUsed = contentSize.height(); qreal previousScroll = vscroll; @@ -1879,14 +1704,15 @@ void QQuickTextInput::invalidateFontCaches() void QQuickTextInput::ensureActiveFocus() { - Q_D(QQuickTextInput); - bool hadActiveFocus = hasActiveFocus(); forceActiveFocus(); #ifndef QT_NO_IM + Q_D(QQuickTextInput); // re-open input panel on press if already focused if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly) qGuiApp->inputMethod()->show(); +#else + Q_UNUSED(hadActiveFocus); #endif } @@ -1920,13 +1746,13 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData node->deleteContent(); node->setMatrix(QMatrix4x4()); - QPointF offset(0, 0); + QPointF offset(leftPadding(), topPadding()); if (d->autoScroll && d->m_textLayout.lineCount() > 0) { QFontMetricsF fm(d->font); // the y offset is there to keep the baseline constant in case we have script changes in the text. - offset = -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent()); + offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent()); } else { - offset = -QPointF(d->hscroll, d->vscroll); + offset += -QPointF(d->hscroll, d->vscroll); } if (!d->m_textLayout.text().isEmpty() @@ -2672,6 +2498,19 @@ bool QQuickTextInput::isInputMethodComposing() const #endif } +QQuickTextInputPrivate::ExtraData::ExtraData() + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) +{ +} + void QQuickTextInputPrivate::init() { Q_Q(QQuickTextInput); @@ -2882,7 +2721,7 @@ qreal QQuickTextInputPrivate::getImplicitWidth() const QTextLine line = layout.createLine(); line.setLineWidth(INT_MAX); - d->implicitWidth = qCeil(line.naturalTextWidth()); + d->implicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding(); layout.endLayout(); } @@ -2890,6 +2729,62 @@ qreal QQuickTextInputPrivate::getImplicitWidth() const return implicitWidth; } +void QQuickTextInputPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->topPaddingChanged(); + } +} + +void QQuickTextInputPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->leftPaddingChanged(); + } +} + +void QQuickTextInputPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->rightPaddingChanged(); + } +} + +void QQuickTextInputPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->bottomPaddingChanged(); + } +} + void QQuickTextInputPrivate::updateLayout() { Q_Q(QQuickTextInput); @@ -2915,12 +2810,12 @@ void QQuickTextInputPrivate::updateLayout() line.setLineWidth(INT_MAX); const bool wasInLayout = inLayout; inLayout = true; - q->setImplicitWidth(qCeil(line.naturalTextWidth())); + q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding()); inLayout = wasInLayout; if (inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. } - qreal lineWidth = q->widthValid() ? q->width() : INT_MAX; + qreal lineWidth = q->widthValid() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX; qreal height = 0; qreal width = 0; do { @@ -2947,9 +2842,9 @@ void QQuickTextInputPrivate::updateLayout() q->update(); if (!requireImplicitWidth && !q->widthValid()) - q->setImplicitSize(width, height); + q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding()); else - q->setImplicitHeight(height); + q->setImplicitHeight(height + q->topPadding() + q->bottomPadding()); updateBaselineOffset(); @@ -2971,13 +2866,13 @@ void QQuickTextInputPrivate::updateBaselineOffset() QFontMetricsF fm(font); qreal yoff = 0; if (q->heightValid()) { - const qreal surplusHeight = q->height() - contentSize.height(); + const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding(); if (vAlign == QQuickTextInput::AlignBottom) yoff = surplusHeight; else if (vAlign == QQuickTextInput::AlignVCenter) yoff = surplusHeight/2; } - q->setBaselineOffset(fm.ascent() + yoff); + q->setBaselineOffset(fm.ascent() + yoff + q->topPadding()); } #ifndef QT_NO_CLIPBOARD @@ -3345,7 +3240,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) m_preeditCursor = event->preeditString().length(); hasImState = !event->preeditString().isEmpty(); bool cursorVisible = true; - QList<QTextLayout::FormatRange> formats; + QVector<QTextLayout::FormatRange> formats; for (int i = 0; i < event->attributes().size(); ++i) { const QInputMethodEvent::Attribute &a = event->attributes().at(i); if (a.type == QInputMethodEvent::Cursor) { @@ -3364,7 +3259,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) } } } - m_textLayout.setAdditionalFormats(formats); + m_textLayout.setFormats(formats); updateDisplayText(/*force*/ true); if ((cursorPositionChanged && !emitCursorPositionChanged()) @@ -4273,6 +4168,21 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) return; } + if (m_blinkPeriod > 0) { + if (m_blinkTimer) + q->killTimer(m_blinkTimer); + + m_blinkTimer = q->startTimer(m_blinkPeriod / 2); + + if (m_blinkStatus == 0) { + m_blinkStatus = 1; + + updateType = UpdatePaintNode; + q->polish(); + q->update(); + } + } + if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing && !m_readOnly @@ -4508,5 +4418,126 @@ void QQuickTextInput::ensureVisible(int position) updateCursorRectangle(false); } +/*! + \since 5.6 + \qmlproperty real QtQuick::TextInput::padding + \qmlproperty real QtQuick::TextInput::topPadding + \qmlproperty real QtQuick::TextInput::leftPadding + \qmlproperty real QtQuick::TextInput::bottomPadding + \qmlproperty real QtQuick::TextInput::rightPadding + + These properties hold the padding around the content. This space is reserved + in addition to the contentWidth and contentHeight. +*/ +qreal QQuickTextInput::padding() const +{ + Q_D(const QQuickTextInput); + return d->padding(); +} + +void QQuickTextInput::setPadding(qreal padding) +{ + Q_D(QQuickTextInput); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + d->updateLayout(); + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickTextInput::resetPadding() +{ + setPadding(0); +} + +qreal QQuickTextInput::topPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickTextInput::setTopPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setTopPadding(padding); +} + +void QQuickTextInput::resetTopPadding() +{ + Q_D(QQuickTextInput); + d->setTopPadding(0, true); +} + +qreal QQuickTextInput::leftPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickTextInput::setLeftPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setLeftPadding(padding); +} + +void QQuickTextInput::resetLeftPadding() +{ + Q_D(QQuickTextInput); + d->setLeftPadding(0, true); +} + +qreal QQuickTextInput::rightPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickTextInput::setRightPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setRightPadding(padding); +} + +void QQuickTextInput::resetRightPadding() +{ + Q_D(QQuickTextInput); + d->setRightPadding(0, true); +} + +qreal QQuickTextInput::bottomPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickTextInput::setBottomPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setBottomPadding(padding); +} + +void QQuickTextInput::resetBottomPadding() +{ + Q_D(QQuickTextInput); + d->setBottomPadding(0, true); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 3bcbe0fa25..b91149f5f3 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -45,13 +45,6 @@ class QValidator; class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) - Q_ENUMS(WrapMode) - Q_ENUMS(EchoMode) - Q_ENUMS(SelectionMode) - Q_ENUMS(CursorPosition) - Q_ENUMS(RenderType) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(int length READ length NOTIFY textChanged) @@ -96,6 +89,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentSizeChanged) Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) + public: QQuickTextInput(QQuickItem * parent=0); ~QQuickTextInput(); @@ -108,18 +107,21 @@ public: Password, PasswordEchoOnEdit }; + Q_ENUM(EchoMode) enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum WrapMode { NoWrap = QTextOption::NoWrap, @@ -128,20 +130,24 @@ public: WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + Q_ENUM(WrapMode) enum SelectionMode { SelectCharacters, SelectWords }; + Q_ENUM(SelectionMode) enum CursorPosition { CursorBetweenCharacters, CursorOnCharacter }; + Q_ENUM(CursorPosition) enum RenderType { QtRendering, NativeRendering }; + Q_ENUM(RenderType) //Auxilliary functions needed to control the TextInput from QML Q_INVOKABLE void positionAt(QQmlV4Function *args) const; @@ -260,6 +266,26 @@ public: qreal contentWidth() const; qreal contentHeight() const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + Q_SIGNALS: void textChanged(); void cursorPositionChanged(); @@ -300,12 +326,19 @@ Q_SIGNALS: void contentSizeChanged(); void inputMethodHintsChanged(); void renderTypeChanged(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); private: void invalidateFontCaches(); void ensureActiveFocus(); protected: + QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent = 0); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; @@ -360,46 +393,8 @@ private: Q_DECLARE_PRIVATE(QQuickTextInput) }; -#ifndef QT_NO_VALIDATOR -class Q_AUTOTEST_EXPORT QQuickIntValidator : public QIntValidator -{ - Q_OBJECT - Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) -public: - QQuickIntValidator(QObject *parent = 0); - - QString localeName() const; - void setLocaleName(const QString &name); - void resetLocaleName(); - -Q_SIGNALS: - void localeNameChanged(); -}; - -class Q_AUTOTEST_EXPORT QQuickDoubleValidator : public QDoubleValidator -{ - Q_OBJECT - Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) -public: - QQuickDoubleValidator(QObject *parent = 0); - - QString localeName() const; - void setLocaleName(const QString &name); - void resetLocaleName(); - -Q_SIGNALS: - void localeNameChanged(); -}; -#endif - QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickTextInput) -#ifndef QT_NO_VALIDATOR -QML_DECLARE_TYPE(QValidator) -QML_DECLARE_TYPE(QQuickIntValidator) -QML_DECLARE_TYPE(QQuickDoubleValidator) -QML_DECLARE_TYPE(QRegExpValidator) -#endif #endif // QQUICKTEXTINPUT_P_H diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 3038573bb3..cf0a6f5273 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -47,6 +47,7 @@ #include <QtGui/qpalette.h> #include <QtGui/qtextlayout.h> #include <QtGui/qstylehints.h> +#include <private/qlazilyallocated_p.h> #include "qplatformdefs.h" @@ -64,13 +65,28 @@ QT_BEGIN_NAMESPACE class QQuickTextNode; -class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate { public: Q_DECLARE_PUBLIC(QQuickTextInput) typedef QQuickTextInput Public; + struct ExtraData { + ExtraData(); + + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; + }; + QLazilyAllocated<ExtraData> extra; + QQuickTextInputPrivate() : hscroll(0) , vscroll(0) @@ -420,6 +436,12 @@ public: qreal getImplicitWidth() const Q_DECL_OVERRIDE; + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + private: void removeSelectedText(); void internalSetText(const QString &txt, int pos = -1, bool edited = true); diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp index 010a443d18..d40dedd798 100644 --- a/src/quick/items/qquicktextnode.cpp +++ b/src/quick/items/qquicktextnode.cpp @@ -186,17 +186,6 @@ void QQuickTextNode::clearCursor() m_cursorNode = 0; } -void QQuickTextNode::initEngine(const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor, const QColor& anchorColor, const QPointF &position) -{ - m_engine.reset(new QQuickTextNodeEngine); - m_engine->m_hasContents = false; - m_engine->setTextColor(textColor); - m_engine->setSelectedTextColor(selectedTextColor); - m_engine->setSelectionColor(selectionColor); - m_engine->setAnchorColor(anchorColor); - m_engine->setPosition(position); -} - void QQuickTextNode::addRectangleNode(const QRectF &rect, const QColor &color) { QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext(); @@ -224,7 +213,12 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex const QColor &selectionColor, const QColor &selectedTextColor, int selectionStart, int selectionEnd) { - initEngine(textColor, selectedTextColor, selectionColor, anchorColor); + QQuickTextNodeEngine engine; + engine.setTextColor(textColor); + engine.setSelectedTextColor(selectedTextColor); + engine.setSelectionColor(selectionColor); + engine.setAnchorColor(anchorColor); + engine.setPosition(position); QList<QTextFrame *> frames; frames.append(textDocument->rootFrame()); @@ -232,7 +226,7 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex QTextFrame *textFrame = frames.takeFirst(); frames.append(textFrame->childFrames()); - m_engine->addFrameDecorations(textDocument, textFrame); + engine.addFrameDecorations(textDocument, textFrame); if (textFrame->firstPosition() > textFrame->lastPosition() && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) { @@ -242,23 +236,23 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex QRectF rect = a->frameBoundingRect(textFrame); QTextBlock block = textFrame->firstCursorPosition().block(); - m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - m_engine->addTextObject(rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument, + engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); + engine.addTextObject(rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument, pos, textFrame->frameFormat().position()); } else { QTextFrame::iterator it = textFrame->begin(); while (!it.atEnd()) { - Q_ASSERT(!m_engine->currentLine().isValid()); + Q_ASSERT(!engine.currentLine().isValid()); QTextBlock block = it.currentBlock(); - m_engine->addTextBlock(textDocument, block, position, textColor, anchorColor, selectionStart, selectionEnd); + engine.addTextBlock(textDocument, block, position, textColor, anchorColor, selectionStart, selectionEnd); ++it; } } } - m_engine->addToSceneGraph(this, style, styleColor); + engine.addToSceneGraph(this, style, styleColor); } void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color, @@ -268,7 +262,12 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay int selectionStart, int selectionEnd, int lineStart, int lineCount) { - initEngine(color, selectedTextColor, selectionColor, anchorColor, position); + QQuickTextNodeEngine engine; + engine.setTextColor(color); + engine.setSelectedTextColor(selectedTextColor); + engine.setSelectionColor(selectionColor); + engine.setAnchorColor(anchorColor); + engine.setPosition(position); #ifndef QT_NO_IM int preeditLength = textLayout->preeditAreaText().length(); @@ -276,7 +275,7 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay #endif QVarLengthArray<QTextLayout::FormatRange> colorChanges; - m_engine->mergeFormats(textLayout, &colorChanges); + engine.mergeFormats(textLayout, &colorChanges); lineCount = lineCount >= 0 ? qMin(lineStart + lineCount, textLayout->lineCount()) @@ -297,11 +296,11 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay } #endif - m_engine->setCurrentLine(line); - m_engine->addGlyphsForRanges(colorChanges, start, end, selectionStart, selectionEnd); + engine.setCurrentLine(line); + engine.addGlyphsForRanges(colorChanges, start, end, selectionStart, selectionEnd); } - m_engine->addToSceneGraph(this, style, styleColor); + engine.addToSceneGraph(this, style, styleColor); } void QQuickTextNode::deleteContent() diff --git a/src/quick/items/qquicktextnode_p.h b/src/quick/items/qquicktextnode_p.h index c7b9804ea6..31cc23bf2a 100644 --- a/src/quick/items/qquicktextnode_p.h +++ b/src/quick/items/qquicktextnode_p.h @@ -101,14 +101,10 @@ public: void setUseNativeRenderer(bool on) { m_useNativeRenderer = on; } private: - void initEngine(const QColor &textColor, const QColor &selectedTextColor, const QColor &selectionColor, const QColor& anchorColor = QColor() - , const QPointF &position = QPointF()); - QSGRectangleNode *m_cursorNode; QList<QSGTexture *> m_textures; QQuickItem *m_ownerElement; bool m_useNativeRenderer; - QScopedPointer<QQuickTextNodeEngine> m_engine; friend class QQuickTextEdit; friend class QQuickTextEditPrivate; diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 7903f79e89..204b135b8c 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -884,7 +884,7 @@ void QQuickTextNodeEngine::mergeFormats(QTextLayout *textLayout, QVarLengthArray if (textLayout == 0) return; - QList<QTextLayout::FormatRange> additionalFormats = textLayout->additionalFormats(); + QVector<QTextLayout::FormatRange> additionalFormats = textLayout->formats(); for (int i=0; i<additionalFormats.size(); ++i) { QTextLayout::FormatRange additionalFormat = additionalFormats.at(i); if (additionalFormat.format.hasProperty(QTextFormat::ForegroundBrush) diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h index 2f6cacf601..f9ebe43183 100644 --- a/src/quick/items/qquicktextnodeengine_p.h +++ b/src/quick/items/qquicktextnodeengine_p.h @@ -231,8 +231,6 @@ private: QList<TextDecoration> m_lines; QVector<BinaryTreeNode> m_processedNodes; - QList<QPair<QRectF, QImage> > m_images; - bool m_hasSelection : 1; bool m_hasContents : 1; friend class QQuickTextNode; diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 5b5413a4ba..6582e3ad40 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -345,6 +345,9 @@ QQuickView::Status QQuickView::status() const if (!d->component) return QQuickView::Null; + if (d->component->status() == QQmlComponent::Ready && !d->root) + return QQuickView::Error; + return QQuickView::Status(d->component->status()); } @@ -364,6 +367,10 @@ QList<QQmlError> QQuickView::errors() const QQmlError error; error.setDescription(QLatin1String("QQuickView: invalid qml engine.")); errs << error; + } else if (d->component->status() == QQmlComponent::Ready && !d->root) { + QQmlError error; + error.setDescription(QLatin1String("QQuickView: invalid root object.")); + errs << error; } return errs; @@ -501,14 +508,15 @@ void QQuickViewPrivate::setRootObject(QObject *obj) if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) { root = sgItem; sgItem->setParentItem(q->QQuickWindow::contentItem()); + } else if (qobject_cast<QWindow *>(obj)) { + qWarning() << "QQuickView does not support using windows as a root item." << endl + << endl + << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl; } else { qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl << endl - << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl - << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl - << endl - << "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl - << "QDeclarativeView class in the Qt Quick 1 module." << endl; + << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl + << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl; delete obj; root = 0; } diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index f094c5a216..80da0ba4f1 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -53,7 +53,6 @@ class Q_QUICK_EXPORT QQuickView : public QQuickWindow Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) - Q_ENUMS(ResizeMode Status) public: explicit QQuickView(QWindow *parent = 0); QQuickView(QQmlEngine* engine, QWindow *parent); @@ -68,10 +67,12 @@ public: QQuickItem *rootObject() const; enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView }; + Q_ENUM(ResizeMode) ResizeMode resizeMode() const; void setResizeMode(ResizeMode); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; QList<QQmlError> errors() const; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 84b585e3b5..6b6b86c1e2 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -83,8 +83,8 @@ bool QQuickWindowPrivate::defaultAlphaBuffer = false; void QQuickWindowPrivate::updateFocusItemTransform() { - Q_Q(QQuickWindow); #ifndef QT_NO_IM + Q_Q(QQuickWindow); QQuickItem *focus = q->activeFocusItem(); if (focus && QGuiApplication::focusObject() == focus) { QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(focus); @@ -259,8 +259,7 @@ void QQuickWindowPrivate::polishItems() // the user. int recursionSafeguard = INT_MAX; while (!itemsToPolish.isEmpty() && --recursionSafeguard > 0) { - QQuickItem *item = *itemsToPolish.begin(); - itemsToPolish.remove(item); + QQuickItem *item = itemsToPolish.takeLast(); QQuickItemPrivate::get(item)->polishScheduled = false; item->updatePolish(); } @@ -2386,7 +2385,9 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem if (target->childMouseEventFilter(item, targetEvent.data())) { qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target; QVector<int> touchIds; - for (int i = 0; i < targetEvent->touchPoints().size(); ++i) + const int touchPointCount = targetEvent->touchPoints().size(); + touchIds.reserve(touchPointCount); + for (int i = 0; i < touchPointCount; ++i) touchIds.append(targetEvent->touchPoints().at(i).id()); target->grabTouchPoints(touchIds); if (mouseGrabberItem) { @@ -2730,7 +2731,7 @@ static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d) QQuickItem *before = 0; for (int i=0; i<childItems.size(); ++i) { QQuickItemPrivate *dd = QQuickItemPrivate::get(childItems.at(i)); - // Perform the same check as the in buildOrderNodeList below. + // Perform the same check as the in fetchNextNode below. if (dd->z() < 0 && (dd->explicitVisible || (dd->extra.isAllocated() && dd->extra->effectRefCount))) before = childItems.at(i); else @@ -2739,13 +2740,9 @@ static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d) return Q_UNLIKELY(before) ? QQuickItemPrivate::get(before)->itemNode() : 0; } -static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) +static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &returnedPaintNode) { QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); - QVector<QSGNode *> desiredNodes; - desiredNodes.reserve(orderedChildren.size() + 1); // + 1 for the paintNode - - int ii = 0; for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) { QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); @@ -2753,11 +2750,14 @@ static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) continue; - desiredNodes.append(childPrivate->itemNode()); + ii++; + return childPrivate->itemNode(); } - if (itemPriv->paintNode) - desiredNodes.append(itemPriv->paintNode); + if (itemPriv->paintNode && !returnedPaintNode) { + returnedPaintNode = true; + return itemPriv->paintNode; + } for (; ii < orderedChildren.count(); ++ii) { QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); @@ -2765,10 +2765,11 @@ static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) continue; - desiredNodes.append(childPrivate->itemNode()); + ii++; + return childPrivate->itemNode(); } - return desiredNodes; + return 0; } void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) @@ -2871,7 +2872,10 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) } if (dirty & QQuickItemPrivate::ChildrenUpdateMask) { - QVector<QSGNode *> desiredNodes = buildOrderedNodeList(itemPriv); + int ii = 0; + bool fetchedPaintNode = false; + QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); + int desiredNodesSize = orderedChildren.size() + (itemPriv->paintNode ? 1 : 0); // now start making current state match the promised land of // desiredNodes. in the case of our current state matching desiredNodes @@ -2889,14 +2893,9 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) int added = 0; int removed = 0; int replaced = 0; -#if defined(CHILDRENUPDATE_DEBUG) - // This is slow! Do not do this in a normal/profiling build! - int initialCount = groupNode->childCount(); -#endif - - while (currentNode && desiredNodesProcessed < desiredNodes.size()) { - QSGNode *desiredNode = desiredNodes.at(desiredNodesProcessed); + QSGNode *desiredNode = 0; + while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) { // uh oh... reality and our utopic paradise are diverging! // we need to reconcile this... if (currentNode != desiredNode) { @@ -2920,9 +2919,8 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) // if we didn't process as many nodes as in the new list, then we have // more nodes at the end of desiredNodes to append to our list. // this will be the case when adding new nodes, for instance. - if (desiredNodesProcessed < desiredNodes.size()) { - for (int i = desiredNodesProcessed; i < desiredNodes.size(); ++i) { - QSGNode *desiredNode = desiredNodes.at(i); + if (desiredNodesProcessed < desiredNodesSize) { + while ((desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) { if (desiredNode->parent()) desiredNode->parent()->removeChildNode(desiredNode); groupNode->appendChildNode(desiredNode); @@ -2939,10 +2937,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) removed++; } } - -#if defined(CHILDRENUPDATE_DEBUG) - qDebug() << "Done children update for " << itemPriv << "- before:" << initialCount << "after:" << groupNode->childCount() << "added:" << added << "removed:" << removed << "replaced:" << replaced; -#endif } if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) { @@ -3308,12 +3302,7 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const QImage QQuickWindow::grabWindow() { Q_D(QQuickWindow); - if (!isVisible()) { - - if (d->context->openglContext()) { - qWarning("QQuickWindow::grabWindow: scene graph already in use"); - return QImage(); - } + if (!isVisible() && !d->context->openglContext()) { if (!handle() || !size().isValid()) { qWarning("QQuickWindow::grabWindow: window must be created and have a valid size"); @@ -3383,6 +3372,11 @@ QQmlIncubationController *QQuickWindow::incubationController() const will delete the GL texture when the texture object is deleted. \value TextureCanUseAtlas The image can be uploaded into a texture atlas. + + \value TextureIsOpaque The texture will return false for + QSGTexture::hasAlphaChannel() and will not be blended. This flag was added + in Qt 5.6. + */ /*! @@ -3587,12 +3581,21 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const The caller of the function is responsible for deleting the returned texture. The actual GL texture will be deleted when the texture object is deleted. - When \a options contains TextureCanUseAtlas the engine may put the image + When \a options contains TextureCanUseAtlas, the engine may put the image into a texture atlas. Textures in an atlas need to rely on QSGTexture::normalizedTextureSubRect() for their geometry and will not support QSGTexture::Repeat. Other values from CreateTextureOption are ignored. + When \a options contains TextureIsOpaque, the engine will create an RGB + texture which returns false for QSGTexture::hasAlphaChannel(). Opaque + textures will in most cases be faster to render. When this flag is not set, + the texture will have an alpha channel based on the image's format. + + When \a options contains TextureHasMipmaps, the engine will create a + texture which can use mipmap filtering. Mipmapped textures can not be in + an atlas. + The returned texture will be using \c GL_TEXTURE_2D as texture target and \c GL_RGBA as internal format. Reimplement QSGTexture to create textures with different parameters. @@ -3614,14 +3617,13 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QQuickWindow); - if (d->context) { - if (options & TextureCanUseAtlas) - return d->context->createTexture(image); - else - return d->context->createTextureNoAtlas(image); - } - else - return 0; + if (!d->context) + return 0; + uint flags = 0; + if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; + if (options & TextureHasMipmaps) flags |= QSGRenderContext::CreateTexture_Mipmap; + if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; + return d->context->createTexture(image, flags); } @@ -4116,6 +4118,7 @@ void QQuickWindow::resetOpenGLState() \value BeforeRenderingStage Before rendering. \value AfterRenderingStage After rendering. \value AfterSwapStage After the frame is swapped. + \value NoStage As soon as possible. This value was added in Qt 5.6. \sa {Scene Graph and Rendering} */ @@ -4141,8 +4144,17 @@ void QQuickWindow::resetOpenGLState() If the rendering is happening on a different thread, then the job will happen on the rendering thread. - \note This function does not trigger rendering; the job - will be stored run until rendering is triggered elsewhere. + If \a stage is \l NoStage, \a job will be run at the earliest opportunity + whenever the render thread is not busy rendering a frame. If there is no + OpenGL context available or the window is not exposed at the time the job is + either posted or handled, it is deleted without executing the run() method. + If a non-threaded renderer is in use, the run() method of the job is executed + synchronously. + The OpenGL context is changed to the renderer context before executing a + \l NoStage job. + + \note This function does not trigger rendering; the jobs targeting any other + stage than NoStage will be stored run until rendering is triggered elsewhere. To force the job to run earlier, call QQuickWindow::update(); \sa beforeRendering(), afterRendering(), beforeSynchronizing(), @@ -4154,16 +4166,22 @@ void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage) Q_D(QQuickWindow); d->renderJobMutex.lock(); - if (stage == BeforeSynchronizingStage) + if (stage == BeforeSynchronizingStage) { d->beforeSynchronizingJobs << job; - else if (stage == AfterSynchronizingStage) + } else if (stage == AfterSynchronizingStage) { d->afterSynchronizingJobs << job; - else if (stage == BeforeRenderingStage) + } else if (stage == BeforeRenderingStage) { d->beforeRenderingJobs << job; - else if (stage == AfterRenderingStage) + } else if (stage == AfterRenderingStage) { d->afterRenderingJobs << job; - else if (stage == AfterSwapStage) + } else if (stage == AfterSwapStage) { d->afterSwapJobs << job; + } else if (stage == NoStage) { + if (isExposed()) + d->windowManager->postJob(this, job); + else + delete job; + } d->renderJobMutex.unlock(); } diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index f7a1956120..eb894d2271 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -69,7 +69,8 @@ public: TextureHasAlphaChannel = 0x0001, TextureHasMipmaps = 0x0002, TextureOwnsGLTexture = 0x0004, - TextureCanUseAtlas = 0x0008 + TextureCanUseAtlas = 0x0008, + TextureIsOpaque = 0x0010, }; enum RenderStage { @@ -77,7 +78,8 @@ public: AfterSynchronizingStage, BeforeRenderingStage, AfterRenderingStage, - AfterSwapStage + AfterSwapStage, + NoStage }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) @@ -85,7 +87,7 @@ public: enum SceneGraphError { ContextNotAvailable = 1 }; - Q_ENUMS(SceneGraphError) + Q_ENUM(SceneGraphError) QQuickWindow(QWindow *parent = 0); explicit QQuickWindow(QQuickRenderControl *renderControl); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 605a36fb1d..0d33d2398a 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -200,7 +200,7 @@ public: QQuickItem *dirtyItemList; QList<QSGNode *> cleanupNodeList; - QSet<QQuickItem *> itemsToPolish; + QVector<QQuickItem *> itemsToPolish; void updateDirtyNodes(); void cleanupNodes(); diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index 524ee02952..6027a6ddc1 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -133,7 +133,6 @@ void QQmlQtQuick2DebugStatesDelegate::updateBinding(QQmlContext *context, QQmlContextData::get(context), fileName, line, column); newBinding->setTarget(property); - newBinding->setNotifyOnValueChanged(true); } state->changeBindingInRevertList(object, propertyName, newBinding); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 63938d50a9..f49fedbbf6 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -198,9 +198,9 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate void ShaderManager::invalidated() { - qDeleteAll(stockShaders.values()); + qDeleteAll(stockShaders); stockShaders.clear(); - qDeleteAll(rewrittenShaders.values()); + qDeleteAll(rewrittenShaders); rewrittenShaders.clear(); delete blitProgram; blitProgram = 0; @@ -1081,6 +1081,9 @@ void Renderer::nodeWasRemoved(Node *node) if (e) { e->removed = true; m_elementsToDelete.add(e); + + if (m_renderNodeElements.isEmpty()) + m_useDepthBuffer = context()->openglContext()->format().depthBufferSize() > 0; } } @@ -2547,8 +2550,15 @@ void Renderer::render() QSGNodeDumper::dump(rootNode()); } - if (Q_UNLIKELY(debug_render() || debug_build())) { + QElapsedTimer timer; + quint64 timeRenderLists = 0; + quint64 timePrepareOpaque = 0; + quint64 timePrepareAlpha = 0; + quint64 timeSorting = 0; + quint64 timeUploadOpaque = 0; + quint64 timeUploadAlpha = 0; + if (Q_UNLIKELY(debug_render() || debug_build())) { QByteArray type("rebuild:"); if (m_rebuild == 0) type += " none"; @@ -2564,6 +2574,7 @@ void Renderer::render() } qDebug() << "Renderer::render()" << this << type; + timer.start(); } if (m_vao) @@ -2590,6 +2601,7 @@ void Renderer::render() } } } + if (Q_UNLIKELY(debug_render())) timeRenderLists = timer.restart(); for (int i=0; i<m_opaqueBatches.size(); ++i) m_opaqueBatches.at(i)->cleanupRemovedElements(); @@ -2602,7 +2614,9 @@ void Renderer::render() if (m_rebuild & BuildBatches) { prepareOpaqueBatches(); + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timer.restart(); prepareAlphaBatches(); + if (Q_UNLIKELY(debug_render())) timePrepareAlpha = timer.restart(); if (Q_UNLIKELY(debug_build())) { qDebug() << "Opaque Batches:"; @@ -2622,8 +2636,11 @@ void Renderer::render() } } } + } else { + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timePrepareAlpha = timer.restart(); } + deleteRemovedElements(); if (m_rebuild != 0) { @@ -2639,6 +2656,8 @@ void Renderer::render() m_zRange = 1.0 / (m_nextRenderOrder); } + if (Q_UNLIKELY(debug_render())) timeSorting = timer.restart(); + int largestVBO = 0; #ifdef QSG_SEPARATE_INDEX_BUFFER int largestIBO = 0; @@ -2653,6 +2672,8 @@ void Renderer::render() #endif uploadBatch(b); } + if (Q_UNLIKELY(debug_render())) timeUploadOpaque = timer.restart(); + if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Alpha Batches:"; for (int i=0; i<m_alphaBatches.size(); ++i) { @@ -2663,6 +2684,7 @@ void Renderer::render() largestIBO = qMax(b->ibo.size, largestIBO); #endif } + if (Q_UNLIKELY(debug_render())) timeUploadAlpha = timer.restart(); if (largestVBO * 2 < m_vertexUploadPool.size()) m_vertexUploadPool.resize(largestVBO * 2); @@ -2673,6 +2695,15 @@ void Renderer::render() renderBatches(); + if (Q_UNLIKELY(debug_render())) { + qDebug(" -> times: build: %d, prepare(opaque/alpha): %d/%d, sorting: %d, upload(opaque/alpha): %d/%d, render: %d", + (int) timeRenderLists, + (int) timePrepareOpaque, (int) timePrepareAlpha, + (int) timeSorting, + (int) timeUploadOpaque, (int) timeUploadAlpha, + (int) timer.elapsed()); + } + m_rebuild = 0; m_renderOrderRebuildLower = -1; m_renderOrderRebuildUpper = -1; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index f87dd75c8c..c7b5f73688 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -100,6 +100,7 @@ template <typename Type, int PageSize> class Allocator { public: Allocator() + : m_freePage(0) { pages.push_back(new AllocatorPage<Type, PageSize>()); } @@ -112,14 +113,21 @@ public: Type *allocate() { AllocatorPage<Type, PageSize> *p = 0; - for (int i=0; i<pages.size(); ++i) { + for (int i = m_freePage; i < pages.size(); i++) { if (pages.at(i)->available > 0) { p = pages.at(i); + m_freePage = i; break; } } + + // we couldn't find a free page from m_freePage to the last page. + // either there is no free pages, or there weren't any in the area we + // scanned: rescanning is expensive, so let's just assume there isn't + // one. when an item is released, we'll reset m_freePage anyway. if (!p) { p = new AllocatorPage<Type, PageSize>(); + m_freePage = pages.count(); pages.push_back(p); } uint pos = p->blocks[PageSize - p->available]; @@ -151,6 +159,9 @@ public: delete page; page = pages.back(); } + + // Reset the free page to force a scan for a new free point. + m_freePage = 0; } void release(Type *t) @@ -172,6 +183,7 @@ public: } QVector<AllocatorPage<Type, PageSize> *> pages; + int m_freePage; }; @@ -500,8 +512,8 @@ public: ShaderManager(QSGRenderContext *ctx) : blitProgram(0), visualizeProgram(0), context(ctx) { } ~ShaderManager() { - qDeleteAll(rewrittenShaders.values()); - qDeleteAll(stockShaders.values()); + qDeleteAll(rewrittenShaders); + qDeleteAll(stockShaders); } public Q_SLOTS: diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 4f5c4efe14..bf97133e97 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -165,7 +165,9 @@ void QSGDistanceFieldGlyphCache::update() Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame); QList<QDistanceField> distanceFields; - for (int i = 0; i < m_pendingGlyphs.size(); ++i) { + const int pendingGlyphsSize = m_pendingGlyphs.size(); + distanceFields.reserve(pendingGlyphsSize); + for (int i = 0; i < pendingGlyphsSize; ++i) { GlyphData &gd = glyphData(m_pendingGlyphs.at(i)); distanceFields.append(QDistanceField(gd.path, m_pendingGlyphs.at(i), diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 418d571ae6..d3879d2958 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -41,7 +41,6 @@ #include <QtQuick/private/qsgdefaultglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h> -#include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h> #include <QtQuick/private/qsgatlastexture_p.h> #include <QtQuick/private/qsgrenderloop_p.h> #include <QtQuick/private/qsgdefaultlayer_p.h> @@ -60,9 +59,6 @@ #include <QtQuick/private/qsgtexture_p.h> #include <QtGui/private/qguiapplication_p.h> #include <QtCore/private/qabstractanimation_p.h> -#include <qpa/qplatformintegration.h> - -#include <qpa/qplatformsharedgraphicscache.h> #include <private/qobject_p.h> #include <qmutex.h> @@ -572,35 +568,7 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); if (!cache) { - QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); - if (platformIntegration != 0 - && platformIntegration->hasCapability(QPlatformIntegration::SharedGraphicsCache)) { - QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; - if (!fe->faceId().filename.isEmpty()) { - QByteArray keyName = fe->faceId().filename; - if (font.style() != QFont::StyleNormal) - keyName += QByteArray(" I"); - if (font.weight() != QFont::Normal) - keyName += ' ' + QByteArray::number(font.weight()); - keyName += QByteArray(" DF"); - QPlatformSharedGraphicsCache *sharedGraphicsCache = - platformIntegration->createPlatformSharedGraphicsCache(keyName); - - if (sharedGraphicsCache != 0) { - sharedGraphicsCache->ensureCacheInitialized(keyName, - QPlatformSharedGraphicsCache::OpenGLTexture, - QPlatformSharedGraphicsCache::Alpha8); - - cache = new QSGSharedDistanceFieldGlyphCache(keyName, - sharedGraphicsCache, - m_distanceFieldCacheManager, - openglContext(), - font); - } - } - } - if (!cache) - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); + cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); m_distanceFieldCacheManager->insertCache(font, cache); } @@ -676,7 +644,7 @@ void QSGRenderContext::invalidate() qDeleteAll(m_texturesToDelete); m_texturesToDelete.clear(); - qDeleteAll(m_textures.values()); + qDeleteAll(m_textures); m_textures.clear(); /* The cleanup of the atlas textures is a bit intriguing. @@ -767,22 +735,26 @@ QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager() will be called with \a image as argument. */ -QSGTexture *QSGRenderContext::createTexture(const QImage &image) const +QSGTexture *QSGRenderContext::createTexture(const QImage &image, uint flags) const { - if (!openglContext()) - return 0; - QSGTexture *t = m_atlasManager->create(image); - if (t) - return t; - return createTextureNoAtlas(image); -} + bool atlas = flags & CreateTexture_Atlas; + bool mipmap = flags & CreateTexture_Mipmap; + bool alpha = flags & CreateTexture_Alpha; -QSGTexture *QSGRenderContext::createTextureNoAtlas(const QImage &image) const -{ - QSGPlainTexture *t = new QSGPlainTexture(); - if (!image.isNull()) - t->setImage(image); - return t; + // The atlas implementation is only supported from the render thread and + // does not support mipmaps. + if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) { + QSGTexture *t = m_atlasManager->create(image, alpha); + if (t) + return t; + } + + QSGPlainTexture *texture = new QSGPlainTexture(); + texture->setImage(image); + if (texture->hasAlphaChannel() && !alpha) + texture->setHasAlphaChannel(false); + + return texture; } /*! diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index d1897f20f9..49b6f6e2a0 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -88,6 +88,12 @@ class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject { Q_OBJECT public: + enum CreateTextureFlags { + CreateTexture_Alpha = 0x1, + CreateTexture_Atlas = 0x2, + CreateTexture_Mipmap = 0x4 + }; + QSGRenderContext(QSGContext *context); ~QSGRenderContext(); @@ -107,8 +113,8 @@ public: virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font); QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window); - virtual QSGTexture *createTexture(const QImage &image) const; - virtual QSGTexture *createTextureNoAtlas(const QImage &image) const; + virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const; + virtual QSGRenderer *createRenderer(); virtual void compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0); diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index c84e6628a5..14bc0fad07 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -104,8 +104,11 @@ char const *const *QSGTextMaskShader::attributeNames() const } QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat) - : QSGMaterialShader(*new QSGMaterialShaderPrivate), - m_glyphFormat(glyphFormat) + : QSGMaterialShader(*new QSGMaterialShaderPrivate) + , m_matrix_id(-1) + , m_color_id(-1) + , m_textureScale_id(-1) + , m_glyphFormat(glyphFormat) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/textmask.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/textmask.frag")); @@ -435,7 +438,9 @@ void QSGTextMaskMaterial::populate(const QPointF &p, { Q_ASSERT(m_font.isValid()); QVector<QFixedPoint> fixedPointPositions; - for (int i=0; i<glyphPositions.size(); ++i) + const int glyphPositionsSize = glyphPositions.size(); + fixedPointPositions.reserve(glyphPositionsSize); + for (int i=0; i < glyphPositionsSize; ++i) fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i))); QTextureGlyphCache *cache = glyphCache(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 7e602fc0bd..4630e45ecf 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -200,9 +200,11 @@ void QSGDistanceFieldGlyphNode::updateGeometry() const QVector<QPointF> positions = m_glyphs.positions(); qreal fontPixelSize = m_glyphs.rawFont().pixelSize(); - QVector<QSGGeometry::TexturedPoint2D> vp; + // The template parameters here are assuming that most strings are short, 64 + // characters or less. + QVarLengthArray<QSGGeometry::TexturedPoint2D, 256> vp; vp.reserve(indexes.size() * 4); - QVector<ushort> ip; + QVarLengthArray<ushort, 384> ip; ip.reserve(indexes.size() * 6); qreal maxTexMargin = m_glyph_cache->distanceFieldRadius(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index 422e31ad96..6f4b85a5b9 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -80,6 +80,11 @@ QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() : QSGMaterialShader(), m_fontScale(1.0) , m_matrixScale(1.0) + , m_matrix_id(-1) + , m_textureScale_id(-1) + , m_alphaMin_id(-1) + , m_alphaMax_id(-1) + , m_color_id(-1) , m_lastAlphaMin(-1) , m_lastAlphaMax(-1) { @@ -260,6 +265,7 @@ protected: DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader() : QSGDistanceFieldTextMaterialShader() + , m_styleColor_id(-1) { } @@ -330,6 +336,8 @@ protected: DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader() : DistanceFieldStyledTextMaterialShader() + , m_outlineAlphaMax0_id(-1) + , m_outlineAlphaMax1_id(-1) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldoutlinetext.frag")); } @@ -411,6 +419,7 @@ protected: DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader() : DistanceFieldStyledTextMaterialShader() + , m_shift_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.frag")); @@ -489,6 +498,8 @@ private: QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader() : QSGDistanceFieldTextMaterialShader() + , m_fontScale_id(-1) + , m_vecDelta_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag")); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index ec9c3c39f9..6c7fb89b6f 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -101,6 +101,22 @@ void QSGRenderLoop::cleanup() s_instance = 0; } +/*! + * Non-threaded render loops immediately run the job if there is a context. + */ +void QSGRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + Q_ASSERT(window); + Q_ASSERT(job); + + if (window->openglContext()) { + window->openglContext()->makeCurrent(window); + job->run(); + } + + delete job; +} + class QSGGuiThreadRenderLoop : public QSGRenderLoop { Q_OBJECT diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 4293015b96..3336731fda 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -45,6 +45,7 @@ class QQuickWindow; class QSGContext; class QSGRenderContext; class QAnimationDriver; +class QRunnable; class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject { @@ -72,6 +73,7 @@ public: virtual QSGRenderContext *createRenderContext(QSGContext *) const = 0; virtual void releaseResources(QQuickWindow *window) = 0; + virtual void postJob(QQuickWindow *window, QRunnable *job); void addWindow(QQuickWindow *win) { m_windows.insert(win); } void removeWindow(QQuickWindow *win) { m_windows.remove(win); } diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp deleted file mode 100644 index f1cc9d1a86..0000000000 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#define EGL_EGLEXT_PROTOTYPES -#define GL_GLEXT_PROTOTYPES -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif - -#include "qsgshareddistancefieldglyphcache_p.h" - -#include <QtCore/qhash.h> -#include <QtCore/qthread.h> -#include <QtCore/qcoreapplication.h> - -#include <qpa/qplatformsharedgraphicscache.h> - -#include <QtQuick/qquickwindow.h> - -// #define QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG - -QT_BEGIN_NAMESPACE - -namespace { - - class QSGInvokeEvent: public QEvent - { - public: - QSGInvokeEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId = QByteArray(), - const QVector<quint32> &glyphIds = QVector<quint32>(), - bool inSceneGraphUpdate = false) - : QEvent(User) - , m_cache(cache) - , m_cacheId(cacheId) - , m_glyphIds(glyphIds) - , m_inSceneGraphUpdate(inSceneGraphUpdate) - {} - - bool inSceneGraphUpdate() const { return m_inSceneGraphUpdate; } - QPlatformSharedGraphicsCache *cache() const { return m_cache; } - - virtual void invoke() = 0; - protected: - QPlatformSharedGraphicsCache *m_cache; - QByteArray m_cacheId; - QVector<quint32> m_glyphIds; - bool m_inSceneGraphUpdate; - }; - - class QSGReleaseItemsEvent: public QSGInvokeEvent - { - public: - QSGReleaseItemsEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId, - const QVector<quint32> &glyphIds, - bool inSceneGraphUpdate) - : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate) - { - } - - void invoke() - { - m_cache->releaseItems(m_cacheId, m_glyphIds); - } - }; - - class QSGRequestItemsEvent: public QSGInvokeEvent - { - public: - QSGRequestItemsEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId, - const QVector<quint32> &glyphIds, - bool inSceneGraphUpdate) - : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate) - { - } - - void invoke() - { - m_cache->requestItems(m_cacheId, m_glyphIds); - } - }; - - class QSGInsertItemsEvent: public QSGInvokeEvent - { - public: - QSGInsertItemsEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId, - const QVector<quint32> &glyphIds, - const QVector<QImage> &images, - bool inSceneGraphUpdate) - : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate) - , m_images(images) - { - } - - void invoke() - { - m_cache->insertItems(m_cacheId, m_glyphIds, m_images); - } - - private: - QVector<QImage> m_images; - }; - - class QSGEndRequestBatchEvent: public QSGInvokeEvent - { - public: - QSGEndRequestBatchEvent(QPlatformSharedGraphicsCache *cache) - : QSGInvokeEvent(cache) - { - } - - void invoke() - { - if (m_cache->requestBatchStarted()) - m_cache->endRequestBatch(); - } - }; - - class QSGMainThreadInvoker: public QObject - { - public: - bool event(QEvent *e) - { - if (e->type() == QEvent::User) { - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - - QSGInvokeEvent *invokeEvent = static_cast<QSGInvokeEvent *>(e); - if (invokeEvent->inSceneGraphUpdate()) { - QPlatformSharedGraphicsCache *cache = invokeEvent->cache(); - if (!cache->requestBatchStarted()) - cache->beginRequestBatch(); - } - - static_cast<QSGInvokeEvent *>(e)->invoke(); - return true; - } - return QObject::event(e); - } - - static QSGMainThreadInvoker *instance() - { - if (m_invoker == 0) { - m_invoker = new QSGMainThreadInvoker; - m_invoker->moveToThread(QCoreApplication::instance()->thread()); - } - - return m_invoker; - } - - private: - static QSGMainThreadInvoker *m_invoker; - }; - - QSGMainThreadInvoker* QSGMainThreadInvoker::m_invoker = 0; -} - -QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId, - QPlatformSharedGraphicsCache *sharedGraphicsCache, - QSGDistanceFieldGlyphCacheManager *man, - QOpenGLContext *c, - const QRawFont &font) - : QSGDistanceFieldGlyphCache(man, c, font) - , m_cacheId(cacheId) - , m_sharedGraphicsCache(sharedGraphicsCache) - , m_isInSceneGraphUpdate(false) - , m_hasPostedEvents(false) -{ -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache with id %s created in thread %p", - cacheId.constData(), QThread::currentThreadId()); -#endif - - Q_ASSERT(sizeof(glyph_t) == sizeof(quint32)); - Q_ASSERT(sharedGraphicsCache != 0); - - connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector<quint32>)), - this, SLOT(reportItemsMissing(QByteArray,QVector<quint32>)), - Qt::DirectConnection); - connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - this, SLOT(reportItemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - Qt::DirectConnection); - connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - this, SLOT(reportItemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - Qt::DirectConnection); - connect(sharedGraphicsCache, SIGNAL(itemsInvalidated(QByteArray,QVector<quint32>)), - this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)), - Qt::DirectConnection); - - Q_ASSERT(c); - QQuickWindow *window = static_cast<QQuickWindow *>(c->surface()); - Q_ASSERT(window != 0); - - connect(window, SIGNAL(beforeSynchronizing()), this, SLOT(sceneGraphUpdateStarted()), - Qt::DirectConnection); - connect(window, SIGNAL(beforeRendering()), this, SLOT(sceneGraphUpdateDone()), - Qt::DirectConnection); -} - -QSGSharedDistanceFieldGlyphCache::~QSGSharedDistanceFieldGlyphCache() -{ - { - QHash<glyph_t, void *>::const_iterator it = m_bufferForGlyph.constBegin(); - while (it != m_bufferForGlyph.constEnd()) { - m_sharedGraphicsCache->dereferenceBuffer(it.value()); - ++it; - } - } - - { - QHash<quint32, PendingGlyph>::const_iterator it = m_pendingReadyGlyphs.constBegin(); - while (it != m_pendingReadyGlyphs.constEnd()) { - m_sharedGraphicsCache->dereferenceBuffer(it.value().buffer); - ++it; - } - } -} - -void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs) -{ - typedef QSet<glyph_t>::const_iterator GlyphSetConstIt; - - QMutexLocker locker(&m_pendingGlyphsMutex); - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::requestGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - m_requestedGlyphsThatHaveNotBeenReturned.unite(glyphs); - m_requestedGlyphs.unite(glyphs); - - QVector<quint32> glyphsVector; - glyphsVector.reserve(glyphs.size()); - - for (GlyphSetConstIt it = glyphs.constBegin(), cend = glyphs.constEnd(); it != cend; ++it) { - Q_ASSERT(!m_bufferForGlyph.contains(*it)); - glyphsVector.append(*it); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGRequestItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphsVector, - m_isInSceneGraphUpdate)); -} - -void QSGSharedDistanceFieldGlyphCache::waitForGlyphs() -{ - Q_ASSERT(!m_isInSceneGraphUpdate); - if (m_isInSceneGraphUpdate) { - qWarning("QSGSharedDistanceFieldGlyphCache::waitForGlyphs: Called from inside " - "scenegraph update. Will freeze."); - } - - { - QMutexLocker locker(&m_pendingGlyphsMutex); - while (!m_requestedGlyphsThatHaveNotBeenReturned.isEmpty()) - m_pendingGlyphsCondition.wait(&m_pendingGlyphsMutex); - } -} - -void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::storeGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - int glyphCount = glyphs.size(); - QVector<quint32> glyphIds(glyphCount); - QVector<QImage> images(glyphCount); - for (int i = 0; i < glyphs.size(); ++i) { - const QDistanceField &df = glyphs.at(i); - m_requestedGlyphsThatHaveNotBeenReturned.insert(df.glyph()); - glyphIds[i] = df.glyph(); - // ### TODO: Handle QDistanceField in QPlatformSharedGraphicsCache - images[i] = df.toImage(QImage::Format_Indexed8); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGInsertItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphIds, - images, - m_isInSceneGraphUpdate)); - } - - processPendingGlyphs(); -} - -void QSGSharedDistanceFieldGlyphCache::referenceGlyphs(const QSet<glyph_t> &glyphs) -{ - Q_UNUSED(glyphs); - - // Intentionally empty. Not required in this implementation, since the glyphs are reference - // counted outside and releaseGlyphs() will only be called when there are no more references. -} - -void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs) -{ - typedef QSet<glyph_t>::const_iterator GlyphSetConstIt; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::releaseGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - m_requestedGlyphs.subtract(glyphs); - - QVector<quint32> glyphsVector; - glyphsVector.reserve(glyphs.size()); - - for (GlyphSetConstIt glyphsIt = glyphs.constBegin(), cend = glyphs.constEnd(); glyphsIt != cend; ++glyphsIt) { - QHash<glyph_t, void *>::iterator bufferIt = m_bufferForGlyph.find(*glyphsIt); - if (bufferIt != m_bufferForGlyph.end()) { - void *buffer = bufferIt.value(); - removeGlyph(*glyphsIt); - m_bufferForGlyph.erase(bufferIt); - Q_ASSERT(!m_bufferForGlyph.contains(*glyphsIt)); - - if (!m_sharedGraphicsCache->dereferenceBuffer(buffer)) { -#if !defined(QT_NO_DEBUG) - bufferIt = m_bufferForGlyph.begin(); - while (bufferIt != m_bufferForGlyph.end()) { - Q_ASSERT(bufferIt.value() != buffer); - ++bufferIt; - } -#endif - } - } - - glyphsVector.append(*glyphsIt); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *mainThreadInvoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(mainThreadInvoker, new QSGReleaseItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphsVector, - m_isInSceneGraphUpdate)); -} - -void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement) -{ - Owner &owner = m_registeredOwners[ownerElement]; - if (owner.ref == 0) { - owner.item = ownerElement; - - bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); - Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot"); - Q_UNUSED(ok); - } - ++owner.ref; -} - -void QSGSharedDistanceFieldGlyphCache::unregisterOwnerElement(QQuickItem *ownerElement) -{ - QHash<QQuickItem *, Owner>::iterator it = m_registeredOwners.find(ownerElement); - if (it != m_registeredOwners.end() && --it->ref <= 0) { - if (it->item) - disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); - m_registeredOwners.erase(it); - } -} - -namespace { - struct TextureContent { - QSize size; - QVector<glyph_t> glyphs; - }; -} - -void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs() -{ - Q_ASSERT(QThread::currentThread() == thread()); - - waitForGlyphs(); - - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_pendingMissingGlyphs.isEmpty() - && m_pendingReadyGlyphs.isEmpty() - && m_pendingInvalidatedGlyphs.isEmpty()) { - return; - } - - { - QVector<glyph_t> pendingMissingGlyphs; - pendingMissingGlyphs.reserve(m_pendingMissingGlyphs.size()); - - QSet<glyph_t>::const_iterator it = m_pendingMissingGlyphs.constBegin(); - while (it != m_pendingMissingGlyphs.constEnd()) { - pendingMissingGlyphs.append(*it); - ++it; - } - - markGlyphsToRender(pendingMissingGlyphs); - } - - { - QVector<glyph_t> filteredPendingInvalidatedGlyphs; - filteredPendingInvalidatedGlyphs.reserve(m_pendingInvalidatedGlyphs.size()); - - QSet<glyph_t>::const_iterator it = m_pendingInvalidatedGlyphs.constBegin(); - while (it != m_pendingInvalidatedGlyphs.constEnd()) { - bool rerequestGlyph = false; - - // The glyph was invalidated right after being posted as ready, we throw away - // the ready glyph and rerequest it to be certain - QHash<quint32, PendingGlyph>::iterator pendingGlyphIt = m_pendingReadyGlyphs.find(*it); - if (pendingGlyphIt != m_pendingReadyGlyphs.end()) { - m_sharedGraphicsCache->dereferenceBuffer(pendingGlyphIt.value().buffer); - pendingGlyphIt = m_pendingReadyGlyphs.erase(pendingGlyphIt); - rerequestGlyph = true; - } - - void *bufferId = m_bufferForGlyph.value(*it, 0); - if (bufferId != 0) { - m_sharedGraphicsCache->dereferenceBuffer(bufferId); - m_bufferForGlyph.remove(*it); - rerequestGlyph = true; - } - - if (rerequestGlyph) - filteredPendingInvalidatedGlyphs.append(*it); - - ++it; - } - - // If this cache is still using the glyphs, reset the texture held by them, and mark them - // to be rendered again since they are still needed. - if (!filteredPendingInvalidatedGlyphs.isEmpty()) { - setGlyphsTexture(filteredPendingInvalidatedGlyphs, Texture()); - markGlyphsToRender(filteredPendingInvalidatedGlyphs); - } - } - - { - QList<GlyphPosition> glyphPositions; - - QHash<void *, TextureContent> textureContentForBuffer; - { - QHash<quint32, PendingGlyph>::iterator it = m_pendingReadyGlyphs.begin(); - while (it != m_pendingReadyGlyphs.end()) { - void *currentGlyphBuffer = m_bufferForGlyph.value(it.key(), 0); - if (currentGlyphBuffer != 0) { - if (!m_sharedGraphicsCache->dereferenceBuffer(currentGlyphBuffer)) { - Q_ASSERT(!textureContentForBuffer.contains(currentGlyphBuffer)); - } - } - - PendingGlyph &pendingGlyph = it.value(); - - // We don't ref or deref the buffer here, since it was already referenced when - // added to the pending ready glyphs - m_bufferForGlyph[it.key()] = pendingGlyph.buffer; - - textureContentForBuffer[pendingGlyph.buffer].size = pendingGlyph.bufferSize; - textureContentForBuffer[pendingGlyph.buffer].glyphs.append(it.key()); - - GlyphPosition glyphPosition; - glyphPosition.glyph = it.key(); - glyphPosition.position = pendingGlyph.position; - - glyphPositions.append(glyphPosition); - - ++it; - } - } - - setGlyphsPosition(glyphPositions); - - { - QHash<void *, TextureContent>::const_iterator it = textureContentForBuffer.constBegin(); - while (it != textureContentForBuffer.constEnd()) { - Texture texture; - texture.textureId = m_sharedGraphicsCache->textureIdForBuffer(it.key()); - texture.size = m_sharedGraphicsCache->sizeOfBuffer(it.key()); - - setGlyphsTexture(it.value().glyphs, texture); - - ++it; - } - } - } - - m_pendingMissingGlyphs.clear(); - m_pendingInvalidatedGlyphs.clear(); - m_pendingReadyGlyphs.clear(); - } -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions) -{ - bool requestedItemsInList = false; - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphsThatHaveNotBeenReturned.contains(itemIds.at(i))) { - requestedItemsInList = true; - break; - } - } - } - - if (requestedItemsInList) - reportItemsUpdated(cacheId, bufferId,itemIds, positions); -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsUpdated(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - - Q_ASSERT(itemIds.size() == positions.size()); - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphs.contains(itemIds.at(i))) { - PendingGlyph &pendingGlyph = m_pendingReadyGlyphs[itemIds.at(i)]; - void *oldBuffer = pendingGlyph.buffer; - - pendingGlyph.buffer = bufferId; - pendingGlyph.position = positions.at(i); - - m_sharedGraphicsCache->referenceBuffer(bufferId); - if (oldBuffer != 0) - m_sharedGraphicsCache->dereferenceBuffer(oldBuffer); - - m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i)); - } - } - } - - m_pendingGlyphsCondition.wakeAll(); - emit glyphsPending(); -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsInvalidated(const QByteArray &cacheId, - const QVector<quint32> &itemIds) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphs.contains(itemIds.at(i))) - m_pendingInvalidatedGlyphs.insert(itemIds.at(i)); - } - } - - emit glyphsPending(); -} - - -void QSGSharedDistanceFieldGlyphCache::reportItemsMissing(const QByteArray &cacheId, - const QVector<quint32> &itemIds) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsMissing() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i))) - m_pendingMissingGlyphs.insert(itemIds.at(i)); - } - } - - m_pendingGlyphsCondition.wakeAll(); - emit glyphsPending(); -} - -void QSGSharedDistanceFieldGlyphCache::sceneGraphUpdateStarted() -{ - m_isInSceneGraphUpdate = true; - m_hasPostedEvents = false; -} - -void QSGSharedDistanceFieldGlyphCache::sceneGraphUpdateDone() -{ - m_isInSceneGraphUpdate = false; - - if (m_hasPostedEvents) { - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGEndRequestBatchEvent(m_sharedGraphicsCache)); - m_hasPostedEvents = false; - } -} - -QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h deleted file mode 100644 index aee77c49c6..0000000000 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSGSHAREDDISTANCEFIELDGLYPHCACHE_H -#define QSGSHAREDDISTANCEFIELDGLYPHCACHE_H - -#include <QtCore/qwaitcondition.h> -#include <private/qsgadaptationlayer_p.h> - -QT_BEGIN_NAMESPACE - -class QPlatformSharedGraphicsCache; -class QSGSharedDistanceFieldGlyphCache : public QObject, public QSGDistanceFieldGlyphCache -{ - Q_OBJECT -public: - explicit QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId, - QPlatformSharedGraphicsCache *sharedGraphicsCache, - QSGDistanceFieldGlyphCacheManager *man, - QOpenGLContext *c, - const QRawFont &font); - ~QSGSharedDistanceFieldGlyphCache(); - - void registerOwnerElement(QQuickItem *ownerElement); - void unregisterOwnerElement(QQuickItem *ownerElement); - void processPendingGlyphs(); - - void requestGlyphs(const QSet<glyph_t> &glyphs); - void referenceGlyphs(const QSet<glyph_t> &glyphs); - void storeGlyphs(const QList<QDistanceField> &glyphs); - void releaseGlyphs(const QSet<glyph_t> &glyphs); - -Q_SIGNALS: - void glyphsPending(); - -private Q_SLOTS: - void reportItemsMissing(const QByteArray &cacheId, const QVector<quint32> &itemIds); - void reportItemsAvailable(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions); - void reportItemsUpdated(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions); - void reportItemsInvalidated(const QByteArray &cacheId, const QVector<quint32> &itemIds); - - void sceneGraphUpdateStarted(); - void sceneGraphUpdateDone(); - -private: - void waitForGlyphs(); - void saveTexture(GLuint textureId, int width, int height); - - QSet<quint32> m_requestedGlyphsThatHaveNotBeenReturned; - QSet<quint32> m_requestedGlyphs; - QWaitCondition m_pendingGlyphsCondition; - QByteArray m_cacheId; - QPlatformSharedGraphicsCache *m_sharedGraphicsCache; - QMutex m_pendingGlyphsMutex; - - QSet<glyph_t> m_pendingInvalidatedGlyphs; - QSet<glyph_t> m_pendingMissingGlyphs; - - struct PendingGlyph - { - PendingGlyph() : buffer(0) {} - - void *buffer; - QSize bufferSize; - QPoint position; - }; - - struct Owner - { - Owner() : ref(0) {} - Owner(const Owner &o) : item(o.item), ref(o.ref) {} - Owner &operator =(const Owner &o) { item = o.item; ref = o.ref; return *this; } - - QPointer<QQuickItem> item; - int ref; - }; - - QHash<quint32, PendingGlyph> m_pendingReadyGlyphs; - QHash<glyph_t, void *> m_bufferForGlyph; - QHash<QQuickItem *, Owner> m_registeredOwners; - - bool m_isInSceneGraphUpdate; - bool m_hasPostedEvents; -}; - -QT_END_NAMESPACE - -#endif // QSGSHAREDDISTANCEFIELDGLYPHCACHE_H diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 56637387df..3b8fdebeed 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -147,6 +147,9 @@ const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); // called. const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5); +// Passed by the window when there is a render job to run +const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6); + template <typename T> T *windowFor(const QList<T> &list, QQuickWindow *window) { for (int i=0; i<list.size(); ++i) { @@ -200,6 +203,14 @@ public: QImage *image; }; +class WMJobEvent : public WMWindowEvent +{ +public: + WMJobEvent(QQuickWindow *c, QRunnable *postedJob) + : WMWindowEvent(c, WM_PostJob), job(postedJob) {} + ~WMJobEvent() { delete job; } + QRunnable *job; +}; class QSGRenderThreadEventQueue : public QQueue<QEvent *> { @@ -345,7 +356,6 @@ bool QSGRenderThread::event(QEvent *e) if (window) { QQuickWindowPrivate::get(window)->fireAboutToStop(); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window removed"; - gl->doneCurrent(); window = 0; } waitCondition.wakeOne(); @@ -396,20 +406,21 @@ bool QSGRenderThread::event(QEvent *e) case WM_Grab: { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Grab"; WMGrabEvent *ce = static_cast<WMGrabEvent *>(e); - Q_ASSERT(ce->window == window); + Q_ASSERT(ce->window); + Q_ASSERT(ce->window == window || !window); mutex.lock(); - if (window) { - gl->makeCurrent(window); + if (ce->window) { + gl->makeCurrent(ce->window); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync scene graph"; - QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + QQuickWindowPrivate *d = QQuickWindowPrivate::get(ce->window); d->syncSceneGraph(); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering scene graph"; - QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize); + QQuickWindowPrivate::get(ce->window)->renderSceneGraph(ce->window->size()); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result"; - *ce->image = qt_gl_read_framebuffer(windowSize * window->effectiveDevicePixelRatio(), false, false); + *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), false, false); } qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result"; waitCondition.wakeOne(); @@ -417,6 +428,20 @@ bool QSGRenderThread::event(QEvent *e) return true; } + case WM_PostJob: { + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_PostJob"; + WMJobEvent *ce = static_cast<WMJobEvent *>(e); + Q_ASSERT(ce->window == window); + if (window) { + gl->makeCurrent(window); + ce->job->run(); + delete ce->job; + ce->job = 0; + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- job done"; + } + return true; + } + case WM_RequestRepaint: qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestPaint"; // When GUI posts this event, it is followed by a polishAndSync, so we mustn't @@ -990,20 +1015,20 @@ void QSGThreadedRenderLoop::maybeUpdate(Window *w) if (!QCoreApplication::instance()) return; + if (!w || !w->thread->isRunning()) + return; + QThread *current = QThread::currentThread(); if (current != QCoreApplication::instance()->thread() && (current != w->thread || !m_lockedForSync)) { qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()"; return; } - if (!w || !w->thread->isRunning()) { - return; - } qCDebug(QSG_LOG_RENDERLOOP) << "update from item" << w->window; // Call this function from the Gui thread later as startTimer cannot be // called from the render thread. - if (QThread::currentThread() == w->thread) { + if (current == w->thread) { qCDebug(QSG_LOG_RENDERLOOP) << "- on render thread"; w->updateDuringSync = true; return; @@ -1239,6 +1264,18 @@ QImage QSGThreadedRenderLoop::grab(QQuickWindow *window) return result; } +/*! + * Posts a new job event to the render thread. + * Returns true if posting succeeded. + */ +void QSGThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + Window *w = windowFor(m_windows, window); + if (w && w->thread && w->thread->window) + w->thread->postEvent(new WMJobEvent(window, job)); + else + delete job; +} #include "qsgthreadedrenderloop.moc" diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index d5ffbf10a3..67df9dcd31 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -71,6 +71,7 @@ public: void releaseResources(QQuickWindow *window); bool event(QEvent *); + void postJob(QQuickWindow *window, QRunnable *job); bool interleaveIncubation() const; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 480ac5e569..84cc2ba135 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -79,7 +79,6 @@ HEADERS += \ $$PWD/qsgdefaultglyphnode_p_p.h \ $$PWD/qsgdefaultimagenode_p.h \ $$PWD/qsgdefaultrectanglenode_p.h \ - $$PWD/qsgshareddistancefieldglyphcache_p.h \ $$PWD/qsgrenderloop_p.h \ $$PWD/qsgthreadedrenderloop_p.h \ $$PWD/qsgwindowsrenderloop_p.h \ @@ -96,7 +95,6 @@ SOURCES += \ $$PWD/qsgdistancefieldglyphnode_p.cpp \ $$PWD/qsgdefaultimagenode.cpp \ $$PWD/qsgdefaultrectanglenode.cpp \ - $$PWD/qsgshareddistancefieldglyphcache.cpp \ $$PWD/qsgrenderloop.cpp \ $$PWD/qsgthreadedrenderloop.cpp \ $$PWD/qsgwindowsrenderloop.cpp \ diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index b862fa6a2b..8c649fb6bd 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -112,13 +112,15 @@ void Manager::invalidate() } } -QSGTexture *Manager::create(const QImage &image) +QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel) { - QSGTexture *t = 0; + Texture *t = 0; if (image.width() < m_atlas_size_limit && image.height() < m_atlas_size_limit) { if (!m_atlas) m_atlas = new Atlas(m_atlas_size); t = m_atlas->create(image); + if (!hasAlphaChannel && t->hasAlphaChannel()) + t->setHasAlphaChannel(false); } return t; } diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h index 399d5fd669..c0f6ab912d 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -58,7 +58,7 @@ public: Manager(); ~Manager(); - QSGTexture *create(const QImage &image); + QSGTexture *create(const QImage &image, bool hasAlphaChannel); void invalidate(); private: @@ -114,6 +114,7 @@ public: int textureId() const { return m_atlas->textureId(); } QSize textureSize() const { return atlasSubRectWithoutPadding().size(); } + void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } bool hasAlphaChannel() const { return m_has_alpha; } bool hasMipmaps() const { return false; } bool isAtlasTexture() const { return true; } diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index c0ddf25765..8622f8edc1 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -150,7 +150,7 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const /*! Creates a texture using the data of \a image - Valid \a options are TextureCanUseAtlas + Valid \a options are TextureCanUseAtlas and TextureIsOpaque. The caller takes ownership of the texture and the texture should only be used with this engine. @@ -160,13 +160,12 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const QSGTexture *QSGEngine::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QSGEngine); - if (!d->sgRenderContext->isValid()) - return 0; - - if (options & TextureCanUseAtlas) - return d->sgRenderContext->createTexture(image); - else - return d->sgRenderContext->createTextureNoAtlas(image); + if (!d->sgRenderContext->isValid()) + return 0; + uint flags = 0; + if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; + if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; + return d->sgRenderContext->createTexture(image, flags); } /*! diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 9a74a02aa1..325d3a9ca2 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -52,7 +52,8 @@ public: enum CreateTextureOption { TextureHasAlphaChannel = 0x0001, TextureOwnsGLTexture = 0x0004, - TextureCanUseAtlas = 0x0008 + TextureCanUseAtlas = 0x0008, + TextureIsOpaque = 0x0010 }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h index 0f6224a831..c4d5cd20cd 100644 --- a/src/quick/util/qquickanimation_p.h +++ b/src/quick/util/qquickanimation_p.h @@ -57,7 +57,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAbstractAnimation : public QObject, public QQ Q_INTERFACES(QQmlParserStatus) Q_INTERFACES(QQmlPropertyValueSource) - Q_ENUMS(Loops) Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(bool alwaysRunToEnd READ alwaysRunToEnd WRITE setAlwaysRunToEnd NOTIFY alwaysRunToEndChanged) @@ -75,6 +74,7 @@ public: virtual ~QQuickAbstractAnimation(); enum Loops { Infinite = -2 }; + Q_ENUM(Loops) bool isRunning() const; void setRunning(bool); @@ -367,7 +367,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimation : public QQuickPropertyAnim { Q_OBJECT Q_DECLARE_PRIVATE(QQuickRotationAnimation) - Q_ENUMS(RotationDirection) Q_PROPERTY(qreal from READ from WRITE setFrom) Q_PROPERTY(qreal to READ to WRITE setTo) @@ -384,6 +383,7 @@ public: void setTo(qreal); enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise }; + Q_ENUM(RotationDirection) RotationDirection direction() const; void setDirection(RotationDirection direction); diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h index 4224c6d9ed..b40e198cc1 100644 --- a/src/quick/util/qquickanimation_p_p.h +++ b/src/quick/util/qquickanimation_p_p.h @@ -164,7 +164,7 @@ private: T *m_instance; }; -class QQuickAbstractAnimationPrivate : public QObjectPrivate, public QAnimationJobChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickAbstractAnimationPrivate : public QObjectPrivate, public QAnimationJobChangeListener { Q_DECLARE_PUBLIC(QQuickAbstractAnimation) public: diff --git a/src/quick/util/qquickanimator_p.h b/src/quick/util/qquickanimator_p.h index 4d3a8e9e4f..7647e582b8 100644 --- a/src/quick/util/qquickanimator_p.h +++ b/src/quick/util/qquickanimator_p.h @@ -136,10 +136,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimator : public QQuickAnimator Q_DECLARE_PRIVATE(QQuickRotationAnimator) Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged) - Q_ENUMS(RotationDirection) - public: enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise }; + Q_ENUM(RotationDirection) QQuickRotationAnimator(QObject *parent = 0); diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 8b617e5e3f..016f41d436 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -126,9 +126,8 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, m_controller->startJob(this, m_job); } else if (newState == Stopped) { syncBackCurrentValues(); - if (m_internalState == State_Starting) - m_internalState = State_Stopped; - else if (m_controller) { + m_internalState = State_Stopped; + if (m_controller) { m_controller->stopJob(this, m_job); } } diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h index 1cffae17db..34c106e89b 100644 --- a/src/quick/util/qquickanimatorjob_p.h +++ b/src/quick/util/qquickanimatorjob_p.h @@ -151,7 +151,6 @@ protected: int m_duration; - uint m_feedback : 1; uint m_isTransform : 1; uint m_isUniform : 1; uint m_hasBeenRunning : 1; diff --git a/src/quick/util/qquickfontloader_p.h b/src/quick/util/qquickfontloader_p.h index b6ca0b3c94..507d0210ee 100644 --- a/src/quick/util/qquickfontloader_p.h +++ b/src/quick/util/qquickfontloader_p.h @@ -46,7 +46,6 @@ class Q_AUTOTEST_EXPORT QQuickFontLoader : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QQuickFontLoader) - Q_ENUMS(Status) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) @@ -54,6 +53,7 @@ class Q_AUTOTEST_EXPORT QQuickFontLoader : public QObject public: enum Status { Null = 0, Ready, Loading, Error }; + Q_ENUM(Status) QQuickFontLoader(QObject *parent = 0); ~QQuickFontLoader(); diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index a231209cd0..70fc3a0973 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -33,6 +33,9 @@ #include "qquickimageprovider.h" +#include "qquickpixmapcache_p.h" +#include <QtQuick/private/qsgcontext_p.h> + QT_BEGIN_NAMESPACE class QQuickImageProviderPrivate @@ -95,6 +98,23 @@ QImage QQuickTextureFactory::image() const return QImage(); } +/*! + Returns a QQuickTextureFactory holding given the image. + + \since 5.6 + */ + +QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage &image) +{ + if (image.isNull()) + return 0; + QQuickTextureFactory *texture = QSGContext::createTextureFactoryFromImage(image); + if (texture) + return texture; + return new QQuickDefaultTextureFactory(image); +} + + /*! \fn QSGTexture *QQuickTextureFactory::createTexture(QQuickWindow *window) const @@ -118,6 +138,67 @@ QImage QQuickTextureFactory::image() const /*! + \class QQuickImageResponse + \since 5.6 + \brief The QQuickImageResponse class provides an interface for asynchronous image loading in QQuickAsyncImageProvider. + \inmodule QtQuick + + The purpose of an image response is to provide a way for image provider jobs to be executed + in an asynchronous way. + + Responses are deleted via \l deleteLater once the finished() signal has been emitted. + If you are using QRunnable as base for your QQuickImageResponse + ensure automatic deletion is disabled. + + \sa QQuickImageProvider +*/ + +/*! + Constructs the image response +*/ +QQuickImageResponse::QQuickImageResponse() +{ +} + +/*! + Destructs the image response +*/ +QQuickImageResponse::~QQuickImageResponse() +{ +} + +/*! + Returns the error string for the job execution. An empty string means no error. +*/ +QString QQuickImageResponse::errorString() const +{ + return QString(); +} + +/*! + This method is used to communicate that the response is no longer required by the engine. + + It may be reimplemented to cancel a request in the provider side, however, it is not mandatory. +*/ +void QQuickImageResponse::cancel() +{ +} + +/*! + \fn void QQuickImageResponse::finished() + + Signals that the job execution has finished (be it successfully, because an error happened or because it was cancelled). + */ + +/*! + \fn QQuickTextureFactory *QQuickImageResponse::textureFactory() const + + Returns the texture factory the job. You can use QQuickTextureFactory::textureFactoryForImage + if your provider works with QImage + */ + + +/*! \class QQuickImageProvider \since 5.0 \inmodule QtQuick @@ -213,7 +294,7 @@ QImage QQuickTextureFactory::image() const To force asynchronous image loading, even for image sources that do not have the \c asynchronous property set to \c true, you may pass the - \c QQuickImageProvider::ForceAsynchronousImageLoading flag to the image + \c QQmlImageProviderBase::ForceAsynchronousImageLoading flag to the image provider constructor. This ensures that all image requests for the provider are handled in a separate thread. @@ -223,6 +304,12 @@ QImage QQuickTextureFactory::image() const if \l {Image::}{asynchronous} is set to \c true, the value is ignored and the image is loaded synchronously. + Asynchronous image loading for providers of type other than ImageResponse are + executed on a single thread per engine basis. That means that a slow image provider + will block the loading of any other request. To avoid that we suggest using QQuickAsyncImageProvider + and implement threading on the provider side via a \c QThreadPool or similar. + See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation. + \section2 Image caching @@ -365,5 +452,41 @@ QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSi return 0; } +/*! + \class QQuickAsyncImageProvider + \since 5.6 + \inmodule QtQuick + \brief The QQuickAsyncImageProvider class provides an interface for for asynchronous control of QML image requests. + + \sa QQuickImageProvider +*/ +QQuickAsyncImageProvider::QQuickAsyncImageProvider() + : QQuickImageProvider(ImageResponse, ForceAsynchronousImageLoading) + , d(0) // just as a placeholder in case we need it for the future +{ + Q_UNUSED(d); +} + +QQuickAsyncImageProvider::~QQuickAsyncImageProvider() +{ +} + +/*! + \fn QQuickImageResponse *QQuickAsyncImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize) + + Implement this method to return the job that will provide the texture with \a id. + + The \a id is the requested image source, with the "image:" scheme and + provider identifier removed. For example, if the image \l{Image::}{source} + was "image://myprovider/icons/home", the given \a id would be "icons/home". + + The \a requestedSize corresponds to the \l {Image::sourceSize} requested by + an Image item. If \a requestedSize is a valid size, the image + returned should be of that size. + + \note this method may be called by multiple threads, so ensure the + implementation of this method is reentrant. +*/ + QT_END_NAMESPACE diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index a2b510f606..cc03eb0fa0 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE class QQuickImageProviderPrivate; +class QQuickAsyncImageProviderPrivate; class QSGTexture; class QQuickWindow; @@ -56,6 +57,25 @@ public: virtual QSize textureSize() const = 0; virtual int textureByteCount() const = 0; virtual QImage image() const; + + static QQuickTextureFactory *textureFactoryForImage(const QImage &image); +}; + +class Q_QUICK_EXPORT QQuickImageResponse : public QObject +{ +Q_OBJECT +public: + QQuickImageResponse(); + virtual ~QQuickImageResponse(); + + virtual QQuickTextureFactory *textureFactory() const = 0; + virtual QString errorString() const; + +public Q_SLOTS: + virtual void cancel(); + +Q_SIGNALS: + void finished(); }; class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase @@ -81,6 +101,18 @@ private: QQuickImageProviderPrivate *d; }; +class Q_QUICK_EXPORT QQuickAsyncImageProvider : public QQuickImageProvider +{ +public: + QQuickAsyncImageProvider(); + virtual ~QQuickAsyncImageProvider(); + + virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) = 0; + +private: + QQuickAsyncImageProviderPrivate *d; +}; + QT_END_NAMESPACE #endif // QQUICKIMAGEPROVIDER_H diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index eea313eeb1..5230a3cdea 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -265,7 +265,7 @@ public: : QQuickCurve(parent), _radiusX(0), _radiusY(0), _useLargeArc(false), _direction(Clockwise) {} enum ArcDirection { Clockwise, Counterclockwise }; - Q_ENUMS(ArcDirection) + Q_ENUM(ArcDirection) qreal radiusX() const; void setRadiusX(qreal); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index ddf2ae2393..f36d06d00d 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -44,7 +44,6 @@ #include <qpa/qplatformintegration.h> #include <QtQuick/private/qsgtexture_p.h> -#include <QtQuick/private/qsgcontext_p.h> #include <QQuickWindow> #include <QCoreApplication> @@ -67,7 +66,7 @@ #include <private/qquickprofiler_p.h> -#define IMAGEREQUEST_MAX_REQUEST_COUNT 8 +#define IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT 8 #define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16 #define CACHE_EXPIRE_TIME 30 #define CACHE_REMOVAL_FRACTION 4 @@ -115,16 +114,6 @@ QSGTexture *QQuickDefaultTextureFactory::createTexture(QQuickWindow *window) con return t; } -static QQuickTextureFactory *textureFactoryForImage(const QImage &image) -{ - if (image.isNull()) - return 0; - QQuickTextureFactory *texture = QSGContext::createTextureFactoryFromImage(image); - if (texture) - return texture; - return new QQuickDefaultTextureFactory(image); -} - class QQuickPixmapReader; class QQuickPixmapData; class QQuickPixmapReply : public QObject @@ -181,6 +170,7 @@ public: virtual bool event(QEvent *e); private slots: void networkRequestDone(); + void asyncResponseFinished(); private: QQuickPixmapReader *reader; }; @@ -205,8 +195,9 @@ protected: private: friend class QQuickPixmapReaderThreadObject; void processJobs(); - void processJob(QQuickPixmapReply *, const QUrl &, const QSize &, AutoTransform); + void processJob(QQuickPixmapReply *, const QUrl &, const QString &, AutoTransform, QQuickImageProvider::ImageType, QQuickImageProvider *); void networkRequestDone(QNetworkReply *); + void asyncResponseFinished(QQuickImageResponse *); QList<QQuickPixmapReply*> jobs; QList<QQuickPixmapReply*> cancelled; @@ -220,7 +211,8 @@ private: QNetworkAccessManager *networkAccessManager(); QNetworkAccessManager *accessManager; - QHash<QNetworkReply*,QQuickPixmapReply*> replies; + QHash<QNetworkReply*,QQuickPixmapReply*> networkJobs; + QHash<QQuickImageResponse*,QQuickPixmapReply*> asyncResponses; static int replyDownloadProgress; static int replyFinished; @@ -439,8 +431,8 @@ QQuickPixmapReader::~QQuickPixmapReader() delete reply; } jobs.clear(); - QList<QQuickPixmapReply*> activeJobs = replies.values(); - foreach (QQuickPixmapReply *reply, activeJobs) { + QList<QQuickPixmapReply*> activeJobs = networkJobs.values() + asyncResponses.values(); + foreach (QQuickPixmapReply *reply, activeJobs ) { if (reply->loading) { cancelled.append(reply); reply->data = 0; @@ -455,7 +447,7 @@ QQuickPixmapReader::~QQuickPixmapReader() void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) { - QQuickPixmapReply *job = replies.take(reply); + QQuickPixmapReply *job = networkJobs.take(reply); if (job) { job->redirectCount++; @@ -472,7 +464,7 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) QMetaObject::connect(reply, replyDownloadProgress, job, downloadProgress); QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone); - replies.insert(reply, job); + networkJobs.insert(reply, job); return; } } @@ -494,7 +486,7 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) // send completion event to the QQuickPixmapReply mutex.lock(); if (!cancelled.contains(job)) - job->postReply(error, errorString, readSize, textureFactoryForImage(image)); + job->postReply(error, errorString, readSize, QQuickTextureFactory::textureFactoryForImage(image)); mutex.unlock(); } reply->deleteLater(); @@ -503,6 +495,32 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) threadObject->processJobs(); } +void QQuickPixmapReader::asyncResponseFinished(QQuickImageResponse *response) +{ + QQuickPixmapReply *job = asyncResponses.take(response); + + if (job) { + QQuickTextureFactory *t = 0; + QQuickPixmapReply::ReadError error = QQuickPixmapReply::NoError; + QString errorString; + QSize readSize; + if (!response->errorString().isEmpty()) { + error = QQuickPixmapReply::Loading; + errorString = response->errorString(); + } else { + t = response->textureFactory(); + } + mutex.lock(); + if (!cancelled.contains(job)) + job->postReply(error, errorString, t->textureSize(), t); + mutex.unlock(); + } + response->deleteLater(); + + // kick off event loop again incase we have dropped below max request count + threadObject->processJobs(); +} + QQuickPixmapReaderThreadObject::QQuickPixmapReaderThreadObject(QQuickPixmapReader *i) : reader(i) { @@ -529,6 +547,12 @@ void QQuickPixmapReaderThreadObject::networkRequestDone() reader->networkRequestDone(reply); } +void QQuickPixmapReaderThreadObject::asyncResponseFinished() +{ + QQuickImageResponse *response = static_cast<QQuickImageResponse *>(sender()); + reader->asyncResponseFinished(response); +} + void QQuickPixmapReader::processJobs() { QMutexLocker locker(&mutex); @@ -538,16 +562,22 @@ void QQuickPixmapReader::processJobs() return; // Nothing else to do // Clean cancelled jobs - if (cancelled.count()) { + if (!cancelled.isEmpty()) { for (int i = 0; i < cancelled.count(); ++i) { QQuickPixmapReply *job = cancelled.at(i); - QNetworkReply *reply = replies.key(job, 0); + QNetworkReply *reply = networkJobs.key(job, 0); if (reply) { - replies.remove(reply); + networkJobs.remove(reply); if (reply->isRunning()) { // cancel any jobs already started reply->close(); } + } else { + QQuickImageResponse *asyncResponse = asyncResponses.key(job); + if (asyncResponse) { + asyncResponses.remove(asyncResponse); + asyncResponse->cancel(); + } } PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url)); // deleteLater, since not owned by this thread @@ -560,27 +590,34 @@ void QQuickPixmapReader::processJobs() // Find a job we can use bool usableJob = false; for (int i = jobs.count() - 1; !usableJob && i >= 0; i--) { - QQuickPixmapReply *runningJob = jobs[i]; - const QUrl url = runningJob->url; + QQuickPixmapReply *job = jobs[i]; + const QUrl url = job->url; + QString localFile; + QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; + QQuickImageProvider *provider = 0; if (url.scheme() == QLatin1String("image")) { + provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); + if (provider) + imageType = provider->imageType(); + usableJob = true; } else { - const QString localFile = QQmlFile::urlToLocalFileOrQrc(url); - usableJob = !localFile.isEmpty() || replies.count() < IMAGEREQUEST_MAX_REQUEST_COUNT; + localFile = QQmlFile::urlToLocalFileOrQrc(url); + usableJob = !localFile.isEmpty() || networkJobs.count() < IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT; } + if (usableJob) { jobs.removeAt(i); - runningJob->loading = true; + job->loading = true; PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url)); - QSize requestSize = runningJob->requestSize; - AutoTransform autoTransform = runningJob->autoTransform; + AutoTransform autoTransform = job->autoTransform; locker.unlock(); - processJob(runningJob, url, requestSize, autoTransform); + processJob(job, url, localFile, autoTransform, imageType, provider); locker.relock(); } } @@ -591,79 +628,97 @@ void QQuickPixmapReader::processJobs() } } -void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, - const QSize &requestSize, AutoTransform autoTransform) +void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile, + AutoTransform autoTransform, QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider) { // fetch if (url.scheme() == QLatin1String("image")) { // Use QQuickImageProvider QSize readSize; - QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; - QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); - if (provider) - imageType = provider->imageType(); + switch (imageType) { + case QQuickImageProvider::Invalid: + { + QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()); + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(QQuickPixmapReply::Loading, errorStr, readSize, 0); + mutex.unlock(); + break; + } - if (imageType == QQuickImageProvider::Invalid) { - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::Loading; - QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()); - QImage image; - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image)); - mutex.unlock(); - } else if (imageType == QQuickImageProvider::Image) { - QImage image = provider->requestImage(imageId(url), &readSize, requestSize); - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; - QString errorStr; - if (image.isNull()) { - errorCode = QQuickPixmapReply::Loading; - errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + case QQuickImageProvider::Image: + { + QImage image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize); + QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; + QString errorStr; + if (image.isNull()) { + errorCode = QQuickPixmapReply::Loading; + errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + } + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(image)); + mutex.unlock(); + break; } - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image)); - mutex.unlock(); - } else if (imageType == QQuickImageProvider::Pixmap) { - const QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize); - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; - QString errorStr; - if (pixmap.isNull()) { - errorCode = QQuickPixmapReply::Loading; - errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + + case QQuickImageProvider::Pixmap: + { + const QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize); + QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; + QString errorStr; + if (pixmap.isNull()) { + errorCode = QQuickPixmapReply::Loading; + errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + } + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage())); + mutex.unlock(); + break; } - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(pixmap.toImage())); - mutex.unlock(); - } else { - QQuickTextureFactory *t = provider->requestTexture(imageId(url), &readSize, requestSize); - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; - QString errorStr; - if (!t) { - errorCode = QQuickPixmapReply::Loading; - errorStr = QQuickPixmap::tr("Failed to get texture from provider: %1").arg(url.toString()); + + case QQuickImageProvider::Texture: + { + QQuickTextureFactory *t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize); + QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; + QString errorStr; + if (!t) { + errorCode = QQuickPixmapReply::Loading; + errorStr = QQuickPixmap::tr("Failed to get texture from provider: %1").arg(url.toString()); + } + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(errorCode, errorStr, readSize, t); + else + delete t; + mutex.unlock(); + break; } - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, t); - else - delete t; - mutex.unlock(); + case QQuickImageProvider::ImageResponse: + { + QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider); + QQuickImageResponse *response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize); + + QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished())); + + asyncResponses.insert(response, runningJob); + break; + } } } else { - QString lf = QQmlFile::urlToLocalFileOrQrc(url); - if (!lf.isEmpty()) { + if (!localFile.isEmpty()) { // Image is local - load/decode immediately QImage image; QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; QString errorStr; - QFile f(lf); + QFile f(localFile); QSize readSize; if (f.open(QIODevice::ReadOnly)) { - if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize, autoTransform)) + if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, autoTransform)) errorCode = QQuickPixmapReply::Loading; } else { errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString()); @@ -671,7 +726,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u } mutex.lock(); if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image)); + runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(image)); mutex.unlock(); } else { // Network resource @@ -682,7 +737,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress); QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone); - replies.insert(reply, runningJob); + networkJobs.insert(reply, runningJob); } } } @@ -775,8 +830,6 @@ inline uint qHash(const QQuickPixmapKey &key) return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.autoTransform * 0x5c5c5c5c); } -class QSGContext; - class QQuickPixmapStore : public QObject { Q_OBJECT @@ -1084,7 +1137,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QImage image = provider->requestImage(imageId(url), &readSize, requestSize); if (!image.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize, autoTransform, UsePluginDefault); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, UsePluginDefault); } } case QQuickImageProvider::Pixmap: @@ -1092,9 +1145,14 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize); if (!pixmap.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(pixmap.toImage()), readSize, requestSize, autoTransform, UsePluginDefault); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, autoTransform, UsePluginDefault); } } + case QQuickImageProvider::ImageResponse: + { + // Fall through, ImageResponse providers never get here + Q_ASSERT(imageType != QQuickImageProvider::ImageResponse && "Sync call to ImageResponse provider"); + } } // provider has bad image type, or provider returned null image @@ -1115,7 +1173,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q AutoTransform appliedTransform = autoTransform; if (readImage(url, &f, &image, &errorString, &readSize, requestSize, appliedTransform)) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform); } errorString = QQuickPixmap::tr("Invalid image data: %1").arg(url.toString()); @@ -1252,7 +1310,7 @@ void QQuickPixmap::setImage(const QImage &p) clear(); if (!p.isNull()) - d = new QQuickPixmapData(this, textureFactoryForImage(p)); + d = new QQuickPixmapData(this, QQuickTextureFactory::textureFactoryForImage(p)); } void QQuickPixmap::setPixmap(const QQuickPixmap &other) diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 6c333c6b13..58d78a5d84 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -145,12 +145,12 @@ public: QQmlBoundSignalExpressionPointer reverseExpression; QQmlBoundSignalExpressionPointer rewindExpression; - virtual void execute(Reason) { + virtual void execute() { QQmlPropertyPrivate::setSignalExpression(property, expression); } virtual bool isReversable() { return true; } - virtual void reverse(Reason) { + virtual void reverse() { QQmlPropertyPrivate::setSignalExpression(property, reverseExpression); } @@ -464,10 +464,10 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions() // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) // so that we can avoid creating then destroying the binding in this case. a.toValue = newBinding->evaluate(); - newBinding->destroy(); + delete newBinding; } else { newBinding->setTarget(prop); - a.toBinding = QQmlAbstractBinding::getPointer(newBinding); + a.toBinding = newBinding; a.deletableToBinding = true; } @@ -558,11 +558,7 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val if (entry.name == name) { expressionIterator.remove(); if (state() && state()->isStateActive()) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name)); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(d->property(name), 0); - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(d->property(name)); d->property(name).write(value); } @@ -624,15 +620,9 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString if (entry.name == name) { entry.expression = expression; if (state() && state()->isStateActive()) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name)); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(d->property(name), 0); - oldBinding->destroy(); - } - QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); newBinding->setTarget(d->property(name)); - QQmlPropertyPrivate::setBinding(d->property(name), newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } return; } @@ -651,7 +641,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); newBinding->setTarget(d->property(name)); - QQmlPropertyPrivate::setBinding(d->property(name), newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } else { QQuickStateAction action; action.restore = restoreEntryValues(); @@ -666,10 +656,10 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) // so that we can avoid creating then destroying the binding in this case. action.toValue = newBinding->evaluate(); - newBinding->destroy(); + delete newBinding; } else { - newBinding->setTarget(d->property(name)); - action.toBinding = QQmlAbstractBinding::getPointer(newBinding); + newBinding->setTarget(action.property); + action.toBinding = newBinding; action.deletableToBinding = true; state()->addEntryToRevertList(action); @@ -677,7 +667,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString if (oldBinding) oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); - QQmlPropertyPrivate::setBinding(action.property, newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } } } diff --git a/src/quick/util/qquicksmoothedanimation_p.h b/src/quick/util/qquicksmoothedanimation_p.h index 68479aa629..efac9217f5 100644 --- a/src/quick/util/qquicksmoothedanimation_p.h +++ b/src/quick/util/qquicksmoothedanimation_p.h @@ -47,7 +47,6 @@ class Q_AUTOTEST_EXPORT QQuickSmoothedAnimation : public QQuickNumberAnimation { Q_OBJECT Q_DECLARE_PRIVATE(QQuickSmoothedAnimation) - Q_ENUMS(ReversingMode) Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged) Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged) @@ -55,6 +54,7 @@ class Q_AUTOTEST_EXPORT QQuickSmoothedAnimation : public QQuickNumberAnimation public: enum ReversingMode { Eased, Immediate, Sync }; + Q_ENUM(ReversingMode) QQuickSmoothedAnimation(QObject *parent = 0); ~QQuickSmoothedAnimation(); diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp index 98d7a76c7e..be676680a6 100644 --- a/src/quick/util/qquickstate.cpp +++ b/src/quick/util/qquickstate.cpp @@ -78,7 +78,7 @@ QQuickStateActionEvent::~QQuickStateActionEvent() { } -void QQuickStateActionEvent::execute(Reason) +void QQuickStateActionEvent::execute() { } @@ -87,7 +87,7 @@ bool QQuickStateActionEvent::isReversable() return false; } -void QQuickStateActionEvent::reverse(Reason) +void QQuickStateActionEvent::reverse() { } @@ -157,11 +157,6 @@ QQuickState::~QQuickState() Q_D(QQuickState); if (d->group) d->group->removeState(this); - - foreach (const QQuickSimpleAction &action, d->revertList) { - if (action.binding()) - action.binding()->destroy(); - } } /*! @@ -361,8 +356,7 @@ void QQuickState::cancel() void QQuickStateAction::deleteFromBinding() { if (fromBinding) { - QQmlPropertyPrivate::setBinding(property, 0); - fromBinding->destroy(); + QQmlPropertyPrivate::removeBinding(property); fromBinding = 0; } } @@ -413,9 +407,6 @@ bool QQuickState::changeBindingInRevertList(QObject *target, const QString &name while (revertListIterator.hasNext()) { QQuickSimpleAction &simpleAction = revertListIterator.next(); if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) { - if (simpleAction.binding()) - simpleAction.binding()->destroy(); - simpleAction.setBinding(binding); return true; } @@ -435,15 +426,11 @@ bool QQuickState::removeEntryFromRevertList(QObject *target, const QString &name while (revertListIterator.hasNext()) { QQuickSimpleAction &simpleAction = revertListIterator.next(); if (simpleAction.property().object() == target && simpleAction.property().name() == name) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(simpleAction.property()); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(simpleAction.property(), 0); - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(simpleAction.property()); simpleAction.property().write(simpleAction.value()); if (simpleAction.binding()) - QQmlPropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding()); + QQmlPropertyPrivate::setBinding(simpleAction.binding()); revertListIterator.remove(); return true; @@ -473,15 +460,11 @@ void QQuickState::removeAllEntriesFromRevertList(QObject *target) while (revertListIterator.hasNext()) { QQuickSimpleAction &simpleAction = revertListIterator.next(); if (simpleAction.property().object() == target) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(simpleAction.property()); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(simpleAction.property(), 0); - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(simpleAction.property()); simpleAction.property().write(simpleAction.value()); if (simpleAction.binding()) - QQmlPropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding()); + QQmlPropertyPrivate::setBinding(simpleAction.binding()); revertListIterator.remove(); } @@ -494,18 +477,15 @@ void QQuickState::addEntriesToRevertList(const QList<QQuickStateAction> &actionL Q_D(QQuickState); if (isStateActive()) { QList<QQuickSimpleAction> simpleActionList; + simpleActionList.reserve(actionList.count()); QListIterator<QQuickStateAction> actionListIterator(actionList); while(actionListIterator.hasNext()) { const QQuickStateAction &action = actionListIterator.next(); QQuickSimpleAction simpleAction(action); action.property.write(action.toValue); - if (!action.toBinding.isNull()) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(simpleAction.property()); - if (oldBinding) - QQmlPropertyPrivate::setBinding(simpleAction.property(), 0); - QQmlPropertyPrivate::setBinding(simpleAction.property(), action.toBinding.data(), QQmlPropertyPrivate::DontRemoveBinding); - } + if (action.toBinding) + QQmlPropertyPrivate::setBinding(action.toBinding.data()); simpleActionList.append(simpleAction); } @@ -619,7 +599,7 @@ void QQuickState::apply(QQuickTransition *trans, QQuickState *revert) for (int jj = 0; jj < d->revertList.count(); ++jj) { if (d->revertList.at(jj).property() == action.property) { found = true; - if (d->revertList.at(jj).binding() != action.fromBinding) { + if (d->revertList.at(jj).binding() != action.fromBinding.data()) { action.deleteFromBinding(); } break; @@ -663,16 +643,13 @@ void QQuickState::apply(QQuickTransition *trans, QQuickState *revert) } if (!found) { QVariant cur = d->revertList.at(ii).property().read(); - QQmlAbstractBinding *delBinding = - QQmlPropertyPrivate::setBinding(d->revertList.at(ii).property(), 0); - if (delBinding) - delBinding->destroy(); + QQmlPropertyPrivate::removeBinding(d->revertList.at(ii).property()); QQuickStateAction a; a.property = d->revertList.at(ii).property(); a.fromValue = cur; a.toValue = d->revertList.at(ii).value(); - a.toBinding = QQmlAbstractBinding::getPointer(d->revertList.at(ii).binding()); + a.toBinding = d->revertList.at(ii).binding(); a.specifiedObject = d->revertList.at(ii).specifiedObject(); a.specifiedProperty = d->revertList.at(ii).specifiedProperty(); a.event = d->revertList.at(ii).event(); diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h index 0c774635d8..1870b70626 100644 --- a/src/quick/util/qquickstate_p.h +++ b/src/quick/util/qquickstate_p.h @@ -39,13 +39,14 @@ #include <QtCore/qobject.h> #include <QtCore/qsharedpointer.h> #include <private/qtquickglobal_p.h> +#include <private/qqmlabstractbinding_p.h> QT_BEGIN_NAMESPACE class QQuickStateActionEvent; -class QQmlAbstractBinding; class QQmlBinding; class QQmlExpression; + class QQuickStateAction { public: @@ -63,8 +64,8 @@ public: QVariant fromValue; QVariant toValue; - QQmlAbstractBinding *fromBinding; - QWeakPointer<QQmlAbstractBinding> toBinding; + QQmlAbstractBinding::Ptr fromBinding; + QQmlAbstractBinding::Ptr toBinding; QQuickStateActionEvent *event; //strictly for matching @@ -80,13 +81,12 @@ public: virtual ~QQuickStateActionEvent(); enum EventType { Script, SignalHandler, ParentChange, AnchorChanges }; - enum Reason { ActualChange, FastForward }; virtual EventType type() const = 0; - virtual void execute(Reason reason = ActualChange); + virtual void execute(); virtual bool isReversable(); - virtual void reverse(Reason reason = ActualChange); + virtual void reverse(); virtual void saveOriginals() {} virtual bool needsCopy() { return false; } virtual void copyOriginals(QQuickStateActionEvent *) {} diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h index fc589f0d2d..e6ecb424e5 100644 --- a/src/quick/util/qquickstate_p_p.h +++ b/src/quick/util/qquickstate_p_p.h @@ -71,7 +71,7 @@ public: if (state == StartState) { m_value = a.fromValue; if (QQmlPropertyPrivate::binding(m_property)) { - m_binding = QQmlAbstractBinding::getPointer(QQmlPropertyPrivate::binding(m_property)); + m_binding = QQmlPropertyPrivate::binding(m_property); } m_reverseEvent = true; } else { @@ -88,7 +88,7 @@ public: QQuickSimpleAction(const QQuickSimpleAction &other) : m_property(other.m_property), m_value(other.m_value), - m_binding(QQmlAbstractBinding::getPointer(other.binding())), + m_binding(other.binding()), m_specifiedObject(other.m_specifiedObject), m_specifiedProperty(other.m_specifiedProperty), m_event(other.m_event), @@ -100,7 +100,7 @@ public: { m_property = other.m_property; m_value = other.m_value; - m_binding = QQmlAbstractBinding::getPointer(other.binding()); + m_binding = other.binding(); m_specifiedObject = other.m_specifiedObject; m_specifiedProperty = other.m_specifiedProperty; m_event = other.m_event; @@ -131,7 +131,7 @@ public: void setBinding(QQmlAbstractBinding *binding) { - m_binding = QQmlAbstractBinding::getPointer(binding); + m_binding = binding; } QQmlAbstractBinding *binding() const @@ -162,7 +162,7 @@ public: private: QQmlProperty m_property; QVariant m_value; - QQmlAbstractBinding::Pointer m_binding; + QQmlAbstractBinding::Ptr m_binding; QObject *m_specifiedObject; QString m_specifiedProperty; QQuickStateActionEvent *m_event; diff --git a/src/quick/util/qquickstatechangescript.cpp b/src/quick/util/qquickstatechangescript.cpp index 6d25b9791d..c276183d62 100644 --- a/src/quick/util/qquickstatechangescript.cpp +++ b/src/quick/util/qquickstatechangescript.cpp @@ -118,7 +118,7 @@ void QQuickStateChangeScript::setName(const QString &n) d->name = n; } -void QQuickStateChangeScript::execute(Reason) +void QQuickStateChangeScript::execute() { Q_D(QQuickStateChangeScript); if (!d->script.isEmpty()) { diff --git a/src/quick/util/qquickstatechangescript_p.h b/src/quick/util/qquickstatechangescript_p.h index 4ff6f0db3e..6c019a43d2 100644 --- a/src/quick/util/qquickstatechangescript_p.h +++ b/src/quick/util/qquickstatechangescript_p.h @@ -62,7 +62,7 @@ public: QString name() const; void setName(const QString &); - virtual void execute(Reason reason = ActualChange); + virtual void execute(); }; diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp index 5efe65ef44..6b1768e9ef 100644 --- a/src/quick/util/qquickstyledtext.cpp +++ b/src/quick/util/qquickstyledtext.cpp @@ -182,7 +182,7 @@ void QQuickStyledText::parse(const QString &string, QTextLayout &layout, void QQuickStyledTextPrivate::parse() { - QList<QTextLayout::FormatRange> ranges; + QVector<QTextLayout::FormatRange> ranges; QStack<QTextCharFormat> formatStack; QString drawText; @@ -283,7 +283,7 @@ void QQuickStyledTextPrivate::parse() } layout.setText(drawText); - layout.setAdditionalFormats(ranges); + layout.setFormats(ranges); } void QQuickStyledTextPrivate::appendText(const QString &textIn, int start, int length, QString &textOut) diff --git a/src/quick/util/qquicksystempalette_p.h b/src/quick/util/qquicksystempalette_p.h index 143efa1c12..fb898eb1fa 100644 --- a/src/quick/util/qquicksystempalette_p.h +++ b/src/quick/util/qquicksystempalette_p.h @@ -45,7 +45,6 @@ class QQuickSystemPalettePrivate; class Q_AUTOTEST_EXPORT QQuickSystemPalette : public QObject { Q_OBJECT - Q_ENUMS(ColorGroup) Q_DECLARE_PRIVATE(QQuickSystemPalette) Q_PROPERTY(QQuickSystemPalette::ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY paletteChanged) @@ -69,6 +68,7 @@ public: ~QQuickSystemPalette(); enum ColorGroup { Active = QPalette::Active, Inactive = QPalette::Inactive, Disabled = QPalette::Disabled }; + Q_ENUM(ColorGroup) QColor window() const; QColor windowText() const; diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp index 74754a0bfb..88fc03bba8 100644 --- a/src/quick/util/qquicktimeline.cpp +++ b/src/quick/util/qquicktimeline.cpp @@ -659,7 +659,7 @@ void QQuickTimeLine::complete() */ void QQuickTimeLine::clear() { - for (QQuickTimeLinePrivate::Ops::const_iterator iter = d->ops.begin(), cend = d->ops.end(); iter != cend; ++iter) + for (QQuickTimeLinePrivate::Ops::const_iterator iter = d->ops.cbegin(), cend = d->ops.cend(); iter != cend; ++iter) iter.key()->_t = 0; d->ops.clear(); d->length = 0; diff --git a/src/quick/util/qquicktransitionmanager.cpp b/src/quick/util/qquicktransitionmanager.cpp index 832596d9a2..3992df993c 100644 --- a/src/quick/util/qquicktransitionmanager.cpp +++ b/src/quick/util/qquicktransitionmanager.cpp @@ -101,8 +101,8 @@ void QQuickTransitionManager::complete() void QQuickTransitionManagerPrivate::applyBindings() { foreach(const QQuickStateAction &action, bindingsList) { - if (!action.toBinding.isNull()) { - QQmlPropertyPrivate::setBinding(action.property, action.toBinding.data()); + if (action.toBinding) { + QQmlPropertyPrivate::setBinding(action.toBinding.data()); } else if (action.event) { if (action.reverseEvent) action.event->reverse(); @@ -131,7 +131,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, if (action.toBinding) d->bindingsList << action; if (action.fromBinding) - QQmlPropertyPrivate::setBinding(action.property, 0); // Disable current binding + QQmlPropertyPrivate::removeBinding(action.property); // Disable current binding if (action.event && action.event->changesBindings()) { //### assume isReversable()? d->bindingsList << action; action.event->clearBindings(); @@ -146,24 +146,21 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, // // This doesn't catch everything, and it might be a little fragile in // some cases - but whatcha going to do? - // - // Note that we only fast forward if both a transition and bindings are - // present, as it is unnecessary (and potentially expensive) otherwise. if (transition && !d->bindingsList.isEmpty()) { // Apply all the property and binding changes for (int ii = 0; ii < applyList.size(); ++ii) { const QQuickStateAction &action = applyList.at(ii); - if (!action.toBinding.isNull()) { - QQmlPropertyPrivate::setBinding(action.property, action.toBinding.data(), QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + if (action.toBinding) { + QQmlPropertyPrivate::setBinding(action.toBinding.data(), QQmlPropertyPrivate::None, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } else if (!action.event) { QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } else if (action.event->isReversable()) { if (action.reverseEvent) - action.event->reverse(QQuickStateActionEvent::FastForward); + action.event->reverse(); else - action.event->execute(QQuickStateActionEvent::FastForward); + action.event->execute(); } } @@ -175,7 +172,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, continue; } const QQmlProperty &prop = action->property; - if (!action->toBinding.isNull() || !action->toValue.isValid()) { + if (action->toBinding || !action->toValue.isValid()) { action->toValue = prop.read(); } } @@ -192,7 +189,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, } if (action.toBinding) - QQmlPropertyPrivate::setBinding(action.property, 0); // Make sure this is disabled during the transition + QQmlPropertyPrivate::removeBinding(action.property); // Make sure this is disabled during the transition QQmlPropertyPrivate::write(action.property, action.fromValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } @@ -269,10 +266,9 @@ void QQuickTransitionManager::cancel() for(int i = 0; i < d->bindingsList.count(); ++i) { QQuickStateAction action = d->bindingsList[i]; - if (!action.toBinding.isNull() && action.deletableToBinding) { - QQmlPropertyPrivate::setBinding(action.property, 0); - action.toBinding.data()->destroy(); - action.toBinding.clear(); + if (action.toBinding && action.deletableToBinding) { + QQmlPropertyPrivate::removeBinding(action.property); + action.toBinding = 0; action.deletableToBinding = false; } else if (action.event) { //### what do we do here? diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 4d156a2d9a..4f6e49fa7a 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -49,6 +49,7 @@ #include "qquicktransition_p.h" #include "qquickanimator_p.h" #include "qquickshortcut_p.h" +#include "qquickvalidator_p.h" #include <qqmlinfo.h> #include <private/qqmltypenotavailable_p.h> #include <private/qquickanimationcontroller_p.h> @@ -87,6 +88,13 @@ void QQuickUtilModule::defineModule() qmlRegisterType<QQuickTransition>("QtQuick",2,0,"Transition"); qmlRegisterType<QQuickVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation"); +#ifndef QT_NO_VALIDATOR + qmlRegisterType<QValidator>(); + qmlRegisterType<QQuickIntValidator>("QtQuick",2,0,"IntValidator"); + qmlRegisterType<QQuickDoubleValidator>("QtQuick",2,0,"DoubleValidator"); + qmlRegisterType<QRegExpValidator>("QtQuick",2,0,"RegExpValidator"); +#endif + qmlRegisterUncreatableType<QQuickAnimator>("QtQuick", 2, 2, "Animator", QQuickAbstractAnimation::tr("Animator is an abstract class")); qmlRegisterType<QQuickXAnimator>("QtQuick", 2, 2, "XAnimator"); qmlRegisterType<QQuickYAnimator>("QtQuick", 2, 2, "YAnimator"); diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp new file mode 100644 index 0000000000..3eebf5d77a --- /dev/null +++ b/src/quick/util/qquickvalidator.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickvalidator_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_VALIDATOR + +/*! + \qmltype IntValidator + \instantiates QIntValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Defines a validator for integer values + + The IntValidator type provides a validator for integer values. + + If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to + interpret the number and will accept locale specific digits, group separators, and positive + and negative signs. In addition, IntValidator is always guaranteed to accept a number + formatted according to the "C" locale. +*/ + +QQuickIntValidator::QQuickIntValidator(QObject *parent) + : QIntValidator(parent) +{ +} + +/*! + \qmlproperty string QtQuick::IntValidator::locale + + This property holds the name of the locale used to interpret the number. + + \sa {QtQml::Qt::locale()}{Qt.locale()} +*/ + +QString QQuickIntValidator::localeName() const +{ + return locale().name(); +} + +void QQuickIntValidator::setLocaleName(const QString &name) +{ + if (locale().name() != name) { + setLocale(QLocale(name)); + emit localeNameChanged(); + } +} + +void QQuickIntValidator::resetLocaleName() +{ + QLocale defaultLocale; + if (locale() != defaultLocale) { + setLocale(defaultLocale); + emit localeNameChanged(); + } +} + +/*! + \qmlproperty int QtQuick::IntValidator::top + + This property holds the validator's highest acceptable value. + By default, this property's value is derived from the highest signed integer available (typically 2147483647). +*/ +/*! + \qmlproperty int QtQuick::IntValidator::bottom + + This property holds the validator's lowest acceptable value. + By default, this property's value is derived from the lowest signed integer available (typically -2147483647). +*/ + +/*! + \qmltype DoubleValidator + \instantiates QDoubleValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Defines a validator for non-integer numbers + + The DoubleValidator type provides a validator for non-integer numbers. + + Input is accepted if it contains a double that is within the valid range + and is in the correct format. + + Input is accepected but invalid if it contains a double that is outside + the range or is in the wrong format; e.g. with too many digits after the + decimal point or is empty. + + Input is rejected if it is not a double. + + Note: If the valid range consists of just positive doubles (e.g. 0.0 to + 100.0) and input is a negative double then it is rejected. If \l notation + is set to DoubleValidator.StandardNotation, and the input contains more + digits before the decimal point than a double in the valid range may have, + it is also rejected. If \l notation is DoubleValidator.ScientificNotation, + and the input is not in the valid range, it is accecpted but invalid. The + value may yet become valid by changing the exponent. +*/ + +QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent) + : QDoubleValidator(parent) +{ +} + +/*! + \qmlproperty string QtQuick::DoubleValidator::locale + + This property holds the name of the locale used to interpret the number. + + \sa {QtQml::Qt::locale()}{Qt.locale()} +*/ + +QString QQuickDoubleValidator::localeName() const +{ + return locale().name(); +} + +void QQuickDoubleValidator::setLocaleName(const QString &name) +{ + if (locale().name() != name) { + setLocale(QLocale(name)); + emit localeNameChanged(); + } +} + +void QQuickDoubleValidator::resetLocaleName() +{ + QLocale defaultLocale; + if (locale() != defaultLocale) { + setLocale(defaultLocale); + emit localeNameChanged(); + } +} + +/*! + \qmlproperty real QtQuick::DoubleValidator::top + + This property holds the validator's maximum acceptable value. + By default, this property contains a value of infinity. +*/ +/*! + \qmlproperty real QtQuick::DoubleValidator::bottom + + This property holds the validator's minimum acceptable value. + By default, this property contains a value of -infinity. +*/ +/*! + \qmlproperty int QtQuick::DoubleValidator::decimals + + This property holds the validator's maximum number of digits after the decimal point. + By default, this property contains a value of 1000. +*/ +/*! + \qmlproperty enumeration QtQuick::DoubleValidator::notation + This property holds the notation of how a string can describe a number. + + The possible values for this property are: + + \list + \li DoubleValidator.StandardNotation + \li DoubleValidator.ScientificNotation (default) + \endlist + + If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2). +*/ + +/*! + \qmltype RegExpValidator + \instantiates QRegExpValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Provides a string validator + + The RegExpValidator type provides a validator, which counts as valid any string which + matches a specified regular expression. +*/ +/*! + \qmlproperty regExp QtQuick::RegExpValidator::regExp + + This property holds the regular expression used for validation. + + Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression + matching "a". + + By default, this property contains a regular expression with the pattern .* that matches any string. +*/ + +#endif // QT_NO_VALIDATOR + +QT_END_NAMESPACE + diff --git a/src/quick/util/qquickvalidator_p.h b/src/quick/util/qquickvalidator_p.h new file mode 100644 index 0000000000..59d7884afc --- /dev/null +++ b/src/quick/util/qquickvalidator_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKVALIDATOR_P_H +#define QQUICKVALIDATOR_P_H + +#include <QtGui/qvalidator.h> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_VALIDATOR +class Q_AUTOTEST_EXPORT QQuickIntValidator : public QIntValidator +{ + Q_OBJECT + Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) +public: + QQuickIntValidator(QObject *parent = 0); + + QString localeName() const; + void setLocaleName(const QString &name); + void resetLocaleName(); + +Q_SIGNALS: + void localeNameChanged(); +}; + +class Q_AUTOTEST_EXPORT QQuickDoubleValidator : public QDoubleValidator +{ + Q_OBJECT + Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) +public: + QQuickDoubleValidator(QObject *parent = 0); + + QString localeName() const; + void setLocaleName(const QString &name); + void resetLocaleName(); + +Q_SIGNALS: + void localeNameChanged(); +}; +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_VALIDATOR +QML_DECLARE_TYPE(QValidator) +QML_DECLARE_TYPE(QQuickIntValidator) +QML_DECLARE_TYPE(QQuickDoubleValidator) +QML_DECLARE_TYPE(QRegExpValidator) +#endif + +#endif // QQUICKVALIDATOR_P_H diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h index f62306ed01..1436d8e310 100644 --- a/src/quick/util/qquickvaluetypes_p.h +++ b/src/quick/util/qquickvaluetypes_p.h @@ -266,8 +266,6 @@ class QQuickFontValueType { QFont v; Q_GADGET - Q_ENUMS(FontWeight) - Q_ENUMS(Capitalization) Q_PROPERTY(QString family READ family WRITE setFamily FINAL) Q_PROPERTY(bool bold READ bold WRITE setBold FINAL) @@ -292,11 +290,13 @@ public: Bold = QFont::Bold, ExtraBold = QFont::ExtraBold, Black = QFont::Black }; + Q_ENUM(FontWeight) enum Capitalization { MixedCase = QFont::MixedCase, AllUppercase = QFont::AllUppercase, AllLowercase = QFont::AllLowercase, SmallCaps = QFont::SmallCaps, Capitalize = QFont::Capitalize }; + Q_ENUM(Capitalization) Q_INVOKABLE QString toString() const; diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index 0e0df4e751..ffb31ae75e 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -29,7 +29,8 @@ SOURCES += \ $$PWD/qquickprofiler.cpp \ $$PWD/qquickfontmetrics.cpp \ $$PWD/qquicktextmetrics.cpp \ - $$PWD/qquickshortcut.cpp + $$PWD/qquickshortcut.cpp \ + $$PWD/qquickvalidator.cpp HEADERS += \ $$PWD/qquickapplication_p.h\ @@ -66,4 +67,5 @@ HEADERS += \ $$PWD/qquickprofiler_p.h \ $$PWD/qquickfontmetrics_p.h \ $$PWD/qquicktextmetrics_p.h \ - $$PWD/qquickshortcut_p.h + $$PWD/qquickshortcut_p.h \ + $$PWD/qquickvalidator_p.h diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index a848774ae9..955abfddb2 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -538,6 +538,9 @@ QQuickWidget::Status QQuickWidget::status() const if (!d->component) return QQuickWidget::Null; + if (d->component->status() == QQmlComponent::Ready && !d->root) + return QQuickWidget::Error; + return QQuickWidget::Status(d->component->status()); } @@ -559,6 +562,10 @@ QList<QQmlError> QQuickWidget::errors() const QQmlError error; error.setDescription(QLatin1String("QQuickWidget: invalid qml engine.")); errs << error; + } else if (d->component->status() == QQmlComponent::Ready && !d->root) { + QQmlError error; + error.setDescription(QLatin1String("QQuickWidget: invalid root object.")); + errs << error; } return errs; @@ -878,14 +885,15 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj) if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) { root = sgItem; sgItem->setParentItem(offscreenWindow->contentItem()); + } else if (qobject_cast<QWindow *>(obj)) { + qWarning() << "QQuickWidget does not support using windows as a root item." << endl + << endl + << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl; } else { qWarning() << "QQuickWidget only supports loading of root objects that derive from QQuickItem." << endl << endl - << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl - << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl - << endl - << "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl - << "QDeclarativeView class in the Qt Quick 1 module." << endl; + << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl + << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl; delete obj; root = 0; } diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index a8bf03edfb..5bb6b49a49 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -56,7 +56,6 @@ class Q_QUICKWIDGETS_EXPORT QQuickWidget : public QWidget Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) - Q_ENUMS(ResizeMode Status) public: explicit QQuickWidget(QWidget *parent = 0); @@ -72,10 +71,12 @@ public: QQuickItem *rootObject() const; enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView }; + Q_ENUM(ResizeMode) ResizeMode resizeMode() const; void setResizeMode(ResizeMode); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; QList<QQmlError> errors() const; diff --git a/sync.profile b/sync.profile index f7255bea0a..28d0698da9 100644 --- a/sync.profile +++ b/sync.profile @@ -7,7 +7,7 @@ "QtQmlDevTools" => "$basedir/src/qmldevtools", ); %moduleheaders = ( # restrict the module headers to those found in relative path - "QtQmlDevTools" => "../qml/parser;../qml/jsruntime;../qml/qml/ftw;../qml/compiler;.", + "QtQmlDevTools" => "../qml/parser;../qml/jsruntime;../qml/qml/ftw;../qml/compiler;../qml/memory;.", ); %deprecatedheaders = ( ); diff --git a/tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST b/tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST new file mode 100644 index 0000000000..2afe6074d7 --- /dev/null +++ b/tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST @@ -0,0 +1,2 @@ +[finishWithUncontrolledAnimation] +* diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro index fc1c0b537b..5a08418be1 100644 --- a/tests/auto/qml/debugger/debugger.pro +++ b/tests/auto/qml/debugger/debugger.pro @@ -12,6 +12,7 @@ PUBLICTESTS += \ PRIVATETESTS += \ qqmldebugclient \ + qqmldebuglocal \ qqmldebugservice SUBDIRS += $$PUBLICTESTS diff --git a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp index 7ca69b6d44..99ba06ae31 100644 --- a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp +++ b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp @@ -76,9 +76,8 @@ void tst_QQmlDebugClient::initTestCase() for (int i = 0; i < 50; ++i) { // try for 5 seconds ... m_conn->connectToHost("127.0.0.1", PORT); - if (m_conn->waitForConnected()) + if (m_conn->waitForConnected(100)) break; - QTest::qSleep(100); } QVERIFY(m_conn->isConnected()); diff --git a/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro b/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro new file mode 100644 index 0000000000..b612da11de --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro @@ -0,0 +1,16 @@ +CONFIG += testcase +TARGET = tst_qqmldebuglocal +osx:CONFIG -= app_bundle + +HEADERS += ../shared/qqmldebugtestservice.h + +SOURCES += tst_qqmldebuglocal.cpp \ + ../shared/qqmldebugtestservice.cpp + +INCLUDEPATH += ../shared +include(../shared/debugutil.pri) + +CONFIG += parallel_test +QT += qml-private testlib gui-private core-private + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 QT_QML_DEBUG_NO_WARNING diff --git a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp new file mode 100644 index 0000000000..b1219eabe4 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QSignalSpy> +#include <QTimer> +#include <QHostAddress> +#include <QDebug> +#include <QThread> +#include <ctime> + +#include "debugutil_p.h" +#include "qqmldebugtestservice.h" + +QString fileName; + +class tst_QQmlDebugLocal : public QObject +{ + Q_OBJECT + +private: + QQmlDebugConnection *m_conn; + + bool connect(); + +signals: + void waiting(); + void parallel(); + +private slots: + void initTestCase(); + + void name(); + void state(); + void sendMessage(); +}; + +void tst_QQmlDebugLocal::initTestCase() +{ + const QString waitingMsg = QString("QML Debugger: Connecting to socket %1...").arg(fileName); + QTest::ignoreMessage(QtDebugMsg, waitingMsg.toLatin1().constData()); + + m_conn = new QQmlDebugConnection(this); + m_conn->startLocalServer(fileName); + + new QQmlEngine(this); + + QQmlDebugTestClient client("tst_QQmlDebugLocal::handshake()", m_conn); + QQmlDebugTestService service("tst_QQmlDebugLocal::handshake()"); + + for (int i = 0; i < 50; ++i) { + // try for 5 seconds ... + if (m_conn->waitForConnected(100)) + break; + } + + QVERIFY(m_conn->isConnected()); + + QTRY_VERIFY(QQmlDebugService::hasDebuggingClient()); + QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled); +} + +void tst_QQmlDebugLocal::name() +{ + QString name = "tst_QQmlDebugLocal::name()"; + + QQmlDebugClient client(name, m_conn); + QCOMPARE(client.name(), name); +} + +void tst_QQmlDebugLocal::state() +{ + { + QQmlDebugConnection dummyConn; + QQmlDebugClient client("tst_QQmlDebugLocal::state()", &dummyConn); + QCOMPARE(client.state(), QQmlDebugClient::NotConnected); + QCOMPARE(client.serviceVersion(), -1.0f); + } + + QQmlDebugTestClient client("tst_QQmlDebugLocal::state()", m_conn); + QCOMPARE(client.state(), QQmlDebugClient::Unavailable); + + { + QQmlDebugTestService service("tst_QQmlDebugLocal::state()", 2); + QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled); + QCOMPARE(client.serviceVersion(), 2.0f); + } + + QTRY_COMPARE(client.state(), QQmlDebugClient::Unavailable); + + // duplicate plugin name + QTest::ignoreMessage(QtWarningMsg, "QQmlDebugClient: Conflicting plugin name \"tst_QQmlDebugLocal::state()\""); + QQmlDebugClient client2("tst_QQmlDebugLocal::state()", m_conn); + QCOMPARE(client2.state(), QQmlDebugClient::NotConnected); + + QQmlDebugClient client3("tst_QQmlDebugLocal::state3()", 0); + QCOMPARE(client3.state(), QQmlDebugClient::NotConnected); +} + +void tst_QQmlDebugLocal::sendMessage() +{ + QQmlDebugTestService service("tst_QQmlDebugLocal::sendMessage()"); + QQmlDebugTestClient client("tst_QQmlDebugLocal::sendMessage()", m_conn); + + QByteArray msg = "hello!"; + + QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled); + + client.sendMessage(msg); + QByteArray resp = client.waitForResponse(); + QCOMPARE(resp, msg); +} + +int main(int argc, char *argv[]) +{ + fileName = QString::fromLatin1("tst_QQmlDebugLocal%1").arg(time(0)); + + int _argc = argc + 1; + char **_argv = new char*[_argc]; + for (int i = 0; i < argc; ++i) + _argv[i] = argv[i]; + char *arg = strdup((QString::fromLatin1("-qmljsdebugger=file:") + fileName).toLatin1().data()); + _argv[_argc - 1] = arg; + + QGuiApplication app(_argc, _argv); + tst_QQmlDebugLocal tc; + return QTest::qExec(&tc, _argc, _argv); + delete _argv; +} + +#include "tst_qqmldebuglocal.moc" diff --git a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.pro b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.pro new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.pro diff --git a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp index de05594161..bb8b8f0823 100644 --- a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp +++ b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp @@ -130,7 +130,7 @@ void tst_QQmlDebugService::name() { QString name = "tst_QQmlDebugService::name()"; - QQmlDebugService service(name, 1); + QQmlDebugTestService service(name, 1); QCOMPARE(service.name(), name); } @@ -138,7 +138,7 @@ void tst_QQmlDebugService::version() { QString name = "tst_QQmlDebugService::name()"; - QQmlDebugService service(name, 2); + QQmlDebugTestService service(name, 2); QCOMPARE(service.version(), 2.0f); } diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index d3bb5c38ca..5090580cc5 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -87,6 +87,8 @@ public: class tst_QQmlEngineDebugService : public QObject { Q_OBJECT +public: + tst_QQmlEngineDebugService() : m_conn(0), m_dbg(0), m_engine(0), m_rootItem(0) {} private: QmlDebugObjectReference findRootObject(int context = 0, @@ -1018,7 +1020,7 @@ void tst_QQmlEngineDebugService::setBindingForObject() mouseAreaObject = m_dbg->object(); onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered"); QCOMPARE(onEnteredRef.name, QString("onEntered")); - QCOMPARE(onEnteredRef.value, QVariant("{console.log('hello, world') }")); + QCOMPARE(onEnteredRef.value, QVariant("function() { [code] }")); } void tst_QQmlEngineDebugService::resetBindingForObject() diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp index 5ed866c04d..23741f2a22 100644 --- a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp +++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp @@ -112,12 +112,14 @@ void tst_QQmlInspector::cleanup() void tst_QQmlInspector::connect() { startQmlsceneProcess("qtquick2.qml"); + QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); } void tst_QQmlInspector::showAppOnTop() { startQmlsceneProcess("qtquick2.qml"); + QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); m_client->setShowAppOnTop(true); @@ -132,6 +134,7 @@ void tst_QQmlInspector::showAppOnTop() void tst_QQmlInspector::reloadQml() { startQmlsceneProcess("qtquick2.qml"); + QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); QByteArray fileContents; @@ -157,6 +160,7 @@ void tst_QQmlInspector::reloadQml() void tst_QQmlInspector::reloadQmlWindow() { startQmlsceneProcess("window.qml"); + QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); QByteArray fileContents; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 094bf43549..8a83c25c19 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -509,7 +509,7 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty void tst_QQmlProfilerService::cleanup() { - if (QTest::currentTestFailed()) { + if (m_client && QTest::currentTestFailed()) { qDebug() << "QML Messages:" << m_client->qmlMessages.count(); int i = 0; foreach (const QQmlProfilerData &data, m_client->qmlMessages) { @@ -547,7 +547,7 @@ void tst_QQmlProfilerService::cleanup() qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null")); qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null")); qDebug() << "Connection State:" << (m_connection ? m_connection->stateString() : QLatin1String("null")); - qDebug() << "Client State:" << (m_client ? m_client->stateString() : QLatin1String("null")); + qDebug() << "Client State:" << m_client->stateString(); } delete m_process; m_process = 0; diff --git a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp index c7281dec69..0f7e572e02 100644 --- a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp +++ b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp @@ -39,6 +39,8 @@ #include <QtCore/qstringlist.h> #include <QtCore/qtimer.h> #include <QtNetwork/qnetworkproxy.h> +#include <QtNetwork/qlocalserver.h> +#include <QtNetwork/qlocalsocket.h> const int protocolVersion = 1; const QString serverId = QLatin1String("QDeclarativeDebugServer"); @@ -61,6 +63,7 @@ public: QQmlDebugConnection *q; QPacketProtocol *protocol; QIODevice *device; + QLocalServer *server; QEventLoop handshakeEventLoop; QTimer handshakeTimer; @@ -72,6 +75,10 @@ public: void connectDeviceSignals(); public Q_SLOTS: + void forwardStateChange(QLocalSocket::LocalSocketState state); + void forwardError(QLocalSocket::LocalSocketError error); + + void newConnection(); void connected(); void readyRead(); void deviceAboutToClose(); @@ -79,7 +86,7 @@ public Q_SLOTS: }; QQmlDebugConnectionPrivate::QQmlDebugConnectionPrivate(QQmlDebugConnection *c) - : QObject(c), q(c), protocol(0), device(0), gotHello(false) + : QObject(c), q(c), protocol(0), device(0), server(0), gotHello(false) { protocol = new QPacketProtocol(q, this); QObject::connect(c, SIGNAL(connected()), this, SLOT(connected())); @@ -307,10 +314,13 @@ void QQmlDebugConnection::close() bool QQmlDebugConnection::waitForConnected(int msecs) { QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device); - if (!socket) - return false; - if (!socket->waitForConnected(msecs)) + if (!socket) { + if (!d->server || (!d->server->hasPendingConnections() && + !d->server->waitForNewConnection(msecs))) + return false; + } else if (!socket->waitForConnected(msecs)) { return false; + } // wait for handshake d->handshakeTimer.start(); d->handshakeEventLoop.exec(); @@ -336,9 +346,13 @@ QString QQmlDebugConnection::stateString() const QAbstractSocket::SocketState QQmlDebugConnection::state() const { - QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device); - if (socket) - return socket->state(); + QAbstractSocket *abstractSocket = qobject_cast<QAbstractSocket*>(d->device); + if (abstractSocket) + return abstractSocket->state(); + + QLocalSocket *localSocket = qobject_cast<QLocalSocket*>(d->device); + if (localSocket) + return static_cast<QAbstractSocket::SocketState>(localSocket->state()); return QAbstractSocket::UnconnectedState; } @@ -366,6 +380,29 @@ void QQmlDebugConnection::connectToHost(const QString &hostName, quint16 port) QIODevice::open(ReadWrite | Unbuffered); } +void QQmlDebugConnection::startLocalServer(const QString &fileName) +{ + d->gotHello = false; + d->server = new QLocalServer(d); + // QueuedConnection so that waitForNewConnection() returns true. + connect(d->server, SIGNAL(newConnection()), d, SLOT(newConnection()), Qt::QueuedConnection); + d->server->listen(fileName); + QIODevice::open(ReadWrite | Unbuffered); +} + +void QQmlDebugConnectionPrivate::newConnection() +{ + QLocalSocket *socket = server->nextPendingConnection(); + server->close(); + device = socket; + connectDeviceSignals(); + connect(socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), + this, SLOT(forwardStateChange(QLocalSocket::LocalSocketState))); + connect(socket, SIGNAL(error(QLocalSocket::LocalSocketError)), + this, SLOT(forwardError(QLocalSocket::LocalSocketError))); + emit q->connected(); +} + void QQmlDebugConnectionPrivate::connectDeviceSignals() { connect(device, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64))); @@ -373,7 +410,15 @@ void QQmlDebugConnectionPrivate::connectDeviceSignals() connect(device, SIGNAL(aboutToClose()), this, SLOT(deviceAboutToClose())); } -// +void QQmlDebugConnectionPrivate::forwardStateChange(QLocalSocket::LocalSocketState state) +{ + emit q->stateChanged(static_cast<QAbstractSocket::SocketState>(state)); +} + +void QQmlDebugConnectionPrivate::forwardError(QLocalSocket::LocalSocketError error) +{ + emit q->error(static_cast<QAbstractSocket::SocketError>(error)); +} QQmlDebugClientPrivate::QQmlDebugClientPrivate() : connection(0) diff --git a/tests/auto/qml/debugger/shared/qqmldebugclient.h b/tests/auto/qml/debugger/shared/qqmldebugclient.h index 52f428cca7..fe9da693c8 100644 --- a/tests/auto/qml/debugger/shared/qqmldebugclient.h +++ b/tests/auto/qml/debugger/shared/qqmldebugclient.h @@ -46,6 +46,7 @@ public: ~QQmlDebugConnection(); void connectToHost(const QString &hostName, quint16 port); + void startLocalServer(const QString &fileName); void setDataStreamVersion(int dataStreamVersion); int dataStreamVersion(); diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index a5c3211f0d..6f1bea6d92 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -36,6 +36,7 @@ PRIVATETESTS += \ qqmldirparser \ qqmlglobal \ qqmllanguage \ + qqmlopenmetaobject \ qqmlproperty \ qqmlpropertycache \ qqmlpropertymap \ @@ -59,7 +60,8 @@ PRIVATETESTS += \ qqmlenginecleanup \ v4misc \ qqmltranslation \ - qqmlimport + qqmlimport \ + qqmlobjectmodel qtHaveModule(widgets) { PUBLICTESTS += \ diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index bb159d5931..4c1f827915 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -110,6 +110,7 @@ private slots: void qmlCreateParentReference(); void async(); void asyncHierarchy(); + void asyncForceSync(); void componentUrlCanonicalization(); void onDestructionLookup(); void onDestructionCount(); @@ -371,6 +372,35 @@ void tst_qqmlcomponent::asyncHierarchy() delete root; } +void tst_qqmlcomponent::asyncForceSync() +{ + { + // 1) make sure that HTTP URLs cannot be completed synchronously + TestHTTPServer server; + QVERIFY2(server.listen(), qPrintable(server.errorString())); + server.serveDirectory(dataDirectory()); + + // ensure that the item hierarchy is compiled correctly. + QQmlComponent component(&engine); + component.loadUrl(server.url("/TestComponent.2.qml"), QQmlComponent::Asynchronous); + QCOMPARE(component.status(), QQmlComponent::Loading); + QQmlComponent component2(&engine, server.url("/TestComponent.2.qml"), QQmlComponent::PreferSynchronous); + QCOMPARE(component2.status(), QQmlComponent::Loading); + } + { + // 2) make sure that file:// URL can be completed synchronously + + // ensure that the item hierarchy is compiled correctly. + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("/TestComponent.2.qml"), QQmlComponent::Asynchronous); + QCOMPARE(component.status(), QQmlComponent::Loading); + QQmlComponent component2(&engine, testFileUrl("/TestComponent.2.qml"), QQmlComponent::PreferSynchronous); + QCOMPARE(component2.status(), QQmlComponent::Ready); + QCOMPARE(component.status(), QQmlComponent::Loading); + QTRY_COMPARE_WITH_TIMEOUT(component.status(), QQmlComponent::Ready, 0); + } +} + void tst_qqmlcomponent::componentUrlCanonicalization() { // ensure that url canonicalization succeeds so that type information diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index bbccf7b94b..eb4a3147d3 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -1253,7 +1253,7 @@ public: Q_INVOKABLE void addReference(QObject *other) { QQmlData *ddata = QQmlData::get(this); - assert(ddata); + Q_ASSERT(ddata); QV4::ExecutionEngine *v4 = ddata->jsWrapper.engine(); Q_ASSERT(v4); QV4::Scope scope(v4); diff --git a/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro b/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro new file mode 100644 index 0000000000..f8232f8854 --- /dev/null +++ b/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +TARGET = tst_qqmlobjectmodel +osx:CONFIG -= app_bundle + +SOURCES += tst_qqmlobjectmodel.cpp + +CONFIG += parallel_test + +QT += qml testlib +QT += core-private qml-private diff --git a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp new file mode 100644 index 0000000000..001739e38d --- /dev/null +++ b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtQml/private/qqmlobjectmodel_p.h> +#include <QtTest/qsignalspy.h> +#include <QtTest/qtest.h> + +class tst_QQmlObjectModel : public QObject +{ + Q_OBJECT + +private slots: + void changes(); +}; + +static bool compareItems(QQmlObjectModel *model, const QObjectList &items) +{ + for (int i = 0; i < items.count(); ++i) { + if (model->get(i) != items.at(i)) + return false; + } + return true; +} + +void tst_QQmlObjectModel::changes() +{ + QQmlObjectModel model; + + QSignalSpy countSpy(&model, SIGNAL(countChanged())); + QSignalSpy childrenSpy(&model, SIGNAL(childrenChanged())); + + int count = 0; + int countSignals = 0; + int childrenSignals = 0; + + QObjectList items; + QObject item0, item1, item2, item3; + + // append(item0) -> [item0] + model.append(&item0); items.append(&item0); + QCOMPARE(model.count(), ++count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // insert(0, item1) -> [item1, item0] + model.insert(0, &item1); items.insert(0, &item1); + QCOMPARE(model.count(), ++count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // append(item2) -> [item1, item0, item2] + model.append(&item2); items.append(&item2); + QCOMPARE(model.count(), ++count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // insert(2, item3) -> [item1, item0, item3, item2] + model.insert(2, &item3); items.insert(2, &item3); + QCOMPARE(model.count(), ++count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // move(0, 1) -> [item0, item1, item3, item2] + model.move(0, 1); items.move(0, 1); + QCOMPARE(model.count(), count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // move(3, 2) -> [item0, item1, item2, item3] + model.move(3, 2); items.move(3, 2); + QCOMPARE(model.count(), count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // remove(0) -> [item1, item2, item3] + model.remove(0); items.removeAt(0); + QCOMPARE(model.count(), --count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // remove(2) -> [item1, item2] + model.remove(2); items.removeAt(2); + QCOMPARE(model.count(), --count); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); + + // clear() -> [] + model.clear(); items.clear(); + QCOMPARE(model.count(), 0); + QVERIFY(compareItems(&model, items)); + QCOMPARE(countSpy.count(), ++countSignals); + QCOMPARE(childrenSpy.count(), ++childrenSignals); +} + +QTEST_MAIN(tst_QQmlObjectModel) + +#include "tst_qqmlobjectmodel.moc" diff --git a/tests/auto/qml/qqmlopenmetaobject/qqmlopenmetaobject.pro b/tests/auto/qml/qqmlopenmetaobject/qqmlopenmetaobject.pro new file mode 100644 index 0000000000..c81394e77e --- /dev/null +++ b/tests/auto/qml/qqmlopenmetaobject/qqmlopenmetaobject.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qqmlopenmetaobject +osx:CONFIG -= app_bundle + +SOURCES += tst_qqmlopenmetaobject.cpp + +CONFIG += parallel_test +QT += core-private gui-private qml-private testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/src/qml/jsruntime/qv4qmlextensions_p.h b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp index e4b9f75298..429f45b875 100644 --- a/src/qml/jsruntime/qv4qmlextensions_p.h +++ b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage @@ -30,29 +30,40 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QV4QMLEXTENSIONS_P_H -#define QV4QMLEXTENSIONS_P_H -#include <qtqmlglobal.h> -#include <qv4global_p.h> +#include <qtest.h> +#include <private/qqmlopenmetaobject_p.h> +#include <QtQml/qqmlengine.h> -QT_BEGIN_NAMESPACE - -namespace QV4 { - -struct Q_QML_EXPORT QmlExtensions +class tst_qqmlopenmetaobject : public QObject { - QmlExtensions() - : valueTypeWrapperPrototype(0) - {} + Q_OBJECT +public: + tst_qqmlopenmetaobject() {} - Heap::Object *valueTypeWrapperPrototype; +private slots: + void createProperties(); +}; - void markObjects(ExecutionEngine *e); +class CustomObject: public QObject +{ + Q_OBJECT +public: + CustomObject(QObject *parent = 0) + : QObject(parent) {} }; -} // namespace QV4 +void tst_qqmlopenmetaobject::createProperties() +{ + QQmlEngine engine; + CustomObject object; + const QQmlRefPointer<QQmlOpenMetaObjectType> mot = new QQmlOpenMetaObjectType(object.metaObject(), &engine); + QQmlOpenMetaObject *const mo = new QQmlOpenMetaObject(&object, mot); + mo->setCached(true); + mot->createProperty("customProperty"); + QVERIFY(true); +} -QT_END_NAMESPACE +QTEST_MAIN(tst_qqmlopenmetaobject) -#endif +#include "tst_qqmlopenmetaobject.moc" diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index c4b2325843..c228adafd4 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -158,10 +158,10 @@ void tst_qqmlproperty::qmlmetaproperty() QObject *obj = new QObject; - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); - QVERIFY(binding != 0); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QCOMPARE(prop.name(), QString()); @@ -189,10 +189,10 @@ void tst_qqmlproperty::qmlmetaproperty() QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -407,10 +407,10 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&object); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); - QVERIFY(binding != 0); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -440,10 +440,10 @@ void tst_qqmlproperty::qmlmetaproperty_object() QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -454,11 +454,11 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&dobject); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -489,11 +489,11 @@ void tst_qqmlproperty::qmlmetaproperty_object() QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int"); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding != 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding); QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -510,10 +510,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&object, QString("defaultProperty")); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); - QVERIFY(binding != 0); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -543,10 +543,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -557,11 +557,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("defaultProperty")); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -592,11 +592,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int"); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding != 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding); QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -607,11 +607,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onClicked")); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -641,10 +641,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(!sigExprWatcher.wasDeleted()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); @@ -656,11 +656,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged")); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -690,10 +690,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(!sigExprWatcher.wasDeleted()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); @@ -711,10 +711,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&object, engine.rootContext()); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); - QVERIFY(binding != 0); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -744,10 +744,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -758,11 +758,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&dobject, engine.rootContext()); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -793,11 +793,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int"); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding != 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding); QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -814,10 +814,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext()); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); - QVERIFY(binding != 0); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -847,10 +847,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -861,11 +861,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext()); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -896,11 +896,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int"); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding != 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding); QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); @@ -911,11 +911,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext()); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -945,10 +945,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(!sigExprWatcher.wasDeleted()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); @@ -960,11 +960,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext()); - QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()))); + QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); - QVERIFY(binding != 0); + QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); - QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr); + QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted()); QObject *obj = new QObject; @@ -994,10 +994,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QQmlPropertyPrivate::binding(prop) == 0); - QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0); - QVERIFY(binding == 0); + QQmlPropertyPrivate::setBinding(prop, binding.data()); + QVERIFY(binding->ref == 1); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0); - QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0); + QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(!sigExprWatcher.wasDeleted()); QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); @@ -1145,7 +1145,7 @@ void tst_qqmlproperty::read() QQmlProperty p(&o, "onClicked"); QCOMPARE(p.read(), QVariant()); - QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1))); + QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1)); QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p)); QCOMPARE(p.read(), QVariant()); @@ -1157,7 +1157,7 @@ void tst_qqmlproperty::read() QQmlProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.read(), QVariant()); - QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1))); + QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1)); QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p)); QCOMPARE(p.read(), QVariant()); @@ -1336,7 +1336,7 @@ void tst_qqmlproperty::write() QQmlProperty p(&o, "onClicked"); QCOMPARE(p.write(QVariant("console.log(1921)")), false); - QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1))); + QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1)); QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p)); QCOMPARE(p.write(QVariant("console.log(1921)")), false); @@ -1350,7 +1350,7 @@ void tst_qqmlproperty::write() QQmlProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.write(QVariant("console.log(1921)")), false); - QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1))); + QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1)); QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p)); QCOMPARE(p.write(QVariant("console.log(1921)")), false); diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/cdata.qml b/tests/auto/qml/qqmlxmlhttprequest/data/cdata.qml index f558fdadc6..e1b690dbf3 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/cdata.qml +++ b/tests/auto/qml/qqmlxmlhttprequest/data/cdata.qml @@ -3,6 +3,7 @@ import QtQuick 2.0 QtObject { property bool xmlTest: false property bool dataOK: false + property int status: 0 function checkCData(text, whitespacetext) { @@ -114,12 +115,11 @@ QtObject { // Test to the end x.onreadystatechange = function() { if (x.readyState == XMLHttpRequest.DONE) { - dataOK = true; + status = x.status; if (x.responseXML != null) checkXML(x.responseXML); - } } diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/json.data b/tests/auto/qml/qqmlxmlhttprequest/data/json.data new file mode 100644 index 0000000000..7925375293 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/json.data @@ -0,0 +1,6 @@ +{"widget": { + "debug": "on", + "window": { + "name": "main_window", + "width": 500 +}}} diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/receiveBinaryData.qml b/tests/auto/qml/qqmlxmlhttprequest/data/receiveBinaryData.qml index 234d759284..b9f0ab6e66 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/receiveBinaryData.qml +++ b/tests/auto/qml/qqmlxmlhttprequest/data/receiveBinaryData.qml @@ -3,6 +3,7 @@ import QtQuick 2.0 QtObject { property string url property int readSize: 0 + property int status: 0 Component.onCompleted: { @@ -12,6 +13,7 @@ QtObject { request.onreadystatechange = function() { if (request.readyState == XMLHttpRequest.DONE) { + status = request.status; var arrayBuffer = request.response; if (arrayBuffer) { var byteArray = new Uint8Array(arrayBuffer); diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/receiveJsonData.qml b/tests/auto/qml/qqmlxmlhttprequest/data/receiveJsonData.qml new file mode 100644 index 0000000000..3fc116e675 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/receiveJsonData.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 + +QtObject { + property string url; + property bool result: false + property string correctjsondata : "{\"widget\":{\"debug\":\"on\",\"window\":{\"name\":\"main_window\",\"width\":500}}}" + + Component.onCompleted: { + var request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "json"; + + request.onreadystatechange = function() { + if (request.readyState == XMLHttpRequest.DONE) { + var jsonData = JSON.stringify(request.response); + result = (correctjsondata == jsonData); + } + } + + request.send(null); + } +} diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect b/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect new file mode 100644 index 0000000000..97b016f50a --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect @@ -0,0 +1,7 @@ +GET /json.data HTTP/1.1 +Accept-Language: en-US,* +Content-Type: application/jsonrequest +Connection: Keep-Alive +Accept-Encoding: gzip, deflate +User-Agent: Mozilla/5.0 +Host: {{ServerHostUrl}} diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.reply b/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.reply new file mode 100644 index 0000000000..f1ee73d623 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.reply @@ -0,0 +1,3 @@ +HTTP/1.1 200 OK +Connection: close +Content-Type: application/jsonrequest diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/text.qml b/tests/auto/qml/qqmlxmlhttprequest/data/text.qml index b79e0bc7b1..972557358b 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/text.qml +++ b/tests/auto/qml/qqmlxmlhttprequest/data/text.qml @@ -3,6 +3,7 @@ import QtQuick 2.0 QtObject { property bool xmlTest: false property bool dataOK: false + property int status: 0 function checkText(text, whitespacetext) { @@ -111,12 +112,11 @@ QtObject { // Test to the end x.onreadystatechange = function() { if (x.readyState == XMLHttpRequest.DONE) { - dataOK = true; + status = x.status; if (x.responseXML != null) checkXML(x.responseXML); - } } diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index c159dc8420..56314a29f5 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -88,6 +88,7 @@ private slots: void getAllResponseHeaders_sent(); void getAllResponseHeaders_args(); void getBinaryData(); + void getJsonData(); void status(); void status_data(); void statusText(); @@ -846,6 +847,24 @@ void tst_qqmlxmlhttprequest::getBinaryData() QFileInfo fileInfo("data/qml_logo.png"); QTRY_VERIFY(object->property("readSize").toInt() == fileInfo.size()); + QCOMPARE(object->property("status").toInt(), 200); +} + +void tst_qqmlxmlhttprequest::getJsonData() +{ + TestHTTPServer server; + QVERIFY2(server.listen(), qPrintable(server.errorString())); + QVERIFY(server.wait(testFileUrl("receive_json_data.expect"), + testFileUrl("receive_binary_data.reply"), + testFileUrl("json.data"))); + + QQmlComponent component(&engine, testFileUrl("receiveJsonData.qml")); + QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); + QVERIFY(!object.isNull()); + object->setProperty("url", server.urlString("/json.data")); + component.completeCreate(); + + QTRY_VERIFY(object->property("result").toBool()); } void tst_qqmlxmlhttprequest::status() @@ -1146,6 +1165,7 @@ void tst_qqmlxmlhttprequest::text() QTRY_VERIFY(object->property("dataOK").toBool() == true); QCOMPARE(object->property("xmlTest").toBool(), true); + QCOMPARE(object->property("status").toInt(), 200); } // Test the CDataSection DOM element @@ -1158,6 +1178,7 @@ void tst_qqmlxmlhttprequest::cdata() QTRY_VERIFY(object->property("dataOK").toBool() == true); QCOMPARE(object->property("xmlTest").toBool(), true); + QCOMPARE(object->property("status").toInt(), 200); } void tst_qqmlxmlhttprequest::stateChangeCallingContext() diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index 056b24d167..ee0f55813d 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -85,7 +85,7 @@ public: QV4::ScopedString name(scope, v4->newString(functionName)); QV4::ScopedContext ctx(scope, v4->rootContext()); QV4::ScopedValue function(scope, BuiltinFunction::create(ctx, name, injectedFunction)); - v4->globalObject()->put(name, function); + v4->globalObject->put(name, function); } signals: @@ -131,7 +131,7 @@ protected: virtual void addObject(const QString &name, const QV4::Value &value) { QV4::Scope scope(engine()); - QV4::ScopedObject obj(scope, value.asObject()); + QV4::ScopedObject obj(scope, value.as<Object>()); QVariantMap props, *prev = &props; qSwap(destination, prev); diff --git a/tests/auto/qmldevtools/compile/tst_compile.cpp b/tests/auto/qmldevtools/compile/tst_compile.cpp index b19260779c..4637f14739 100644 --- a/tests/auto/qmldevtools/compile/tst_compile.cpp +++ b/tests/auto/qmldevtools/compile/tst_compile.cpp @@ -37,7 +37,6 @@ #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlirbuilder_p.h> -#include <private/qv4value_inl_p.h> #include <private/qv4codegen_p.h> int main() diff --git a/tests/auto/qmltest/BLACKLIST b/tests/auto/qmltest/BLACKLIST new file mode 100644 index 0000000000..cd8b1181e0 --- /dev/null +++ b/tests/auto/qmltest/BLACKLIST @@ -0,0 +1,5 @@ +# Blacklist for testing +[SelfTests::test_blacklisted_fail] +* +[SelfTests::test_blacklistWithData:test2] +* diff --git a/tests/auto/qmltest/objectmodel/tst_objectmodel.qml b/tests/auto/qmltest/objectmodel/tst_objectmodel.qml new file mode 100644 index 0000000000..e8205a1486 --- /dev/null +++ b/tests/auto/qmltest/objectmodel/tst_objectmodel.qml @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml 2.1 +import QtQml.Models 2.3 +import QtTest 1.1 + +TestCase { + name: "ObjectModel" + + ObjectModel { + id: model + QtObject { id: static0 } + QtObject { id: static1 } + QtObject { id: static2 } + } + + Component { id: object; QtObject { } } + + function test_attached_index() { + compare(model.count, 3) + compare(static0.ObjectModel.index, 0) + compare(static1.ObjectModel.index, 1) + compare(static2.ObjectModel.index, 2) + + var dynamic0 = object.createObject(model, {objectName: "dynamic0"}) + compare(dynamic0.ObjectModel.index, -1) + model.append(dynamic0) // -> [static0, static1, static2, dynamic0] + compare(model.count, 4) + for (var i = 0; i < model.count; ++i) + compare(model.get(i).ObjectModel.index, i) + + var dynamic1 = object.createObject(model, {objectName: "dynamic1"}) + compare(dynamic1.ObjectModel.index, -1) + model.insert(0, dynamic1) // -> [dynamic1, static0, static1, static2, dynamic0] + compare(model.count, 5) + for (i = 0; i < model.count; ++i) + compare(model.get(i).ObjectModel.index, i) + + model.move(1, 3) // -> [dynamic1, static1, static2, static0, dynamic0] + compare(model.count, 5) + for (i = 0; i < model.count; ++i) + compare(model.get(i).ObjectModel.index, i) + + model.move(4, 0) // -> [dynamic0, dynamic1, static1, static2, static0] + compare(model.count, 5) + for (i = 0; i < model.count; ++i) + compare(model.get(i).ObjectModel.index, i) + + model.remove(1) // -> [dynamic0, static1, static2, static0] + compare(model.count, 4) + compare(dynamic1.ObjectModel.index, -1) + for (i = 0; i < model.count; ++i) + compare(model.get(i).ObjectModel.index, i) + + model.clear() + compare(static0.ObjectModel.index, -1) + compare(static1.ObjectModel.index, -1) + compare(static2.ObjectModel.index, -1) + compare(dynamic0.ObjectModel.index, -1) + compare(dynamic1.ObjectModel.index, -1) + } +} diff --git a/tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml b/tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml new file mode 100644 index 0000000000..9de9a621f6 --- /dev/null +++ b/tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQml.Models 2.3 +import QtTest 1.1 + +Item { + id: top + + ListView { + id: listViewWithObjectModel // QTBUG-46798 + anchors.fill: parent + model: ObjectModel { + id: objectModel + Rectangle { width: 160; height: 160; color: "red" } + Rectangle { width: 160; height: 160; color: "green" } + Rectangle { width: 160; height: 160; color: "blue" } + } + } + + TestCase { + name: "QTBUG-46798" + when: windowShown + + function test_bug46798() { + var item = objectModel.get(0) + if (item) { + objectModel.remove(0) + item.destroy() + } + } + } +} diff --git a/src/qml/jsruntime/qv4qmlextensions.cpp b/tests/auto/qmltest/selftests/tst_grabImage.qml index c1c4e0ec78..7a758ae8fc 100644 --- a/src/qml/jsruntime/qv4qmlextensions.cpp +++ b/tests/auto/qmltest/selftests/tst_grabImage.qml @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage @@ -31,13 +31,28 @@ ** ****************************************************************************/ -#include "qv4qmlextensions_p.h" -#include "qv4object_p.h" +import QtQuick 2.0 +import QtTest 1.1 -using namespace QV4; +TestCase { + id: testCase + name: "tst_grabImage" + when: windowShown -void QmlExtensions::markObjects(ExecutionEngine *e) -{ - if (valueTypeWrapperPrototype) - valueTypeWrapperPrototype->mark(e); + function test_equals() { + var rect = Qt.createQmlObject("import QtQuick 2.0; Rectangle { color: 'red'; width: 10; height: 10; }", testCase); + verify(rect); + var oldImage = grabImage(rect); + rect.width += 10; + var newImage = grabImage(rect); + verify(!newImage.equals(oldImage)); + + oldImage = grabImage(rect); + // Don't change anything... + newImage = grabImage(rect); + verify(newImage.equals(oldImage)); + + verify(!newImage.equals(null)); + verify(!newImage.equals(undefined)); + } } diff --git a/tests/auto/qmltest/selftests/tst_selftests.qml b/tests/auto/qmltest/selftests/tst_selftests.qml index 0d09f9536a..a372107e26 100644 --- a/tests/auto/qmltest/selftests/tst_selftests.qml +++ b/tests/auto/qmltest/selftests/tst_selftests.qml @@ -278,4 +278,30 @@ TestCase { } verify(caught) } + + function test_blacklisted_fail() + { + verify(false) + } + + function test_blacklistWithData_data() { + return [ + { + tag: "test1", + success: true + }, + { + tag: "test2", + success: false + }, + { + tag: "test3", + success: true + } + ] + } + + function test_blacklistWithData(row) { + verify(row.success) + } } diff --git a/tests/auto/qmltest/textedit/tst_textedit_editingfinished.qml b/tests/auto/qmltest/textedit/tst_textedit_editingfinished.qml new file mode 100644 index 0000000000..c9eadde373 --- /dev/null +++ b/tests/auto/qmltest/textedit/tst_textedit_editingfinished.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtTest 1.1 + +Row { + width: 100 + height: 50 + spacing: 10 + + property alias control1: _control1 + property alias control2: _control2 + TextEdit { + id: _control1 + text: 'A' + property bool myeditingfinished: false + onEditingFinished: myeditingfinished = true + activeFocusOnTab: true + } + TextEdit { + id: _control2 + text: 'B' + property bool myeditingfinished: false + onEditingFinished: myeditingfinished = true + activeFocusOnTab: true + } + + TestCase { + name: "TextEdit_editingFinished" + when: windowShown + + function test_editingFinished() { + control1.forceActiveFocus() + verify(control1.activeFocus) + verify(!control2.activeFocus) + + verify(control1.myeditingfinished === false) + verify(control2.myeditingfinished === false) + + keyClick(Qt.Key_Backtab) + verify(!control1.activeFocus) + verify(control2.activeFocus) + verify(control1.myeditingfinished === true) + + keyClick(Qt.Key_Backtab) + verify(control1.activeFocus) + verify(!control2.activeFocus) + verify(control2.myeditingfinished === true) + } + } +} diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp index 378af7ea90..58746447f0 100644 --- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp +++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp @@ -67,7 +67,6 @@ #include <QtQuick/private/qsgrenderer_p.h> #include <QtQuick/private/qsgrenderloop_p.h> #include <QtQuick/private/qsgrendernode_p.h> -#include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h> #include <QtQuick/private/qsgtexturematerial_p.h> #include <QtQuick/private/qsgtexture_p.h> #include <QtQuick/private/qsgthreadedrenderloop_p.h> diff --git a/tests/auto/quick/qquickbehaviors/BLACKLIST b/tests/auto/quick/qquickbehaviors/BLACKLIST new file mode 100644 index 0000000000..9be4da176d --- /dev/null +++ b/tests/auto/quick/qquickbehaviors/BLACKLIST @@ -0,0 +1,2 @@ +[currentValue] +windows diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp index b96f1de930..643bed4376 100644 --- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp +++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp @@ -82,39 +82,35 @@ void tst_qquickbehaviors::simpleBehavior() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("simple.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QTRY_VERIFY(qobject_cast<QQuickBehavior*>(rect->findChild<QQuickBehavior*>("MyBehavior"))->animation()); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() > 0); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() < 200); //i.e. the behavior has been triggered - - delete rect; } void tst_qquickbehaviors::scriptTriggered() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("scripttrigger.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); rect->setColor(QColor("red")); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() > 0); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() < 200); //i.e. the behavior has been triggered - - delete rect; } void tst_qquickbehaviors::cppTriggered() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("cpptrigger.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); QTRY_VERIFY(innerRect); @@ -122,60 +118,52 @@ void tst_qquickbehaviors::cppTriggered() innerRect->setProperty("x", 200); QTRY_VERIFY(innerRect->x() > 0); QTRY_VERIFY(innerRect->x() < 200); //i.e. the behavior has been triggered - - delete rect; } void tst_qquickbehaviors::loop() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("loop.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); //don't crash - QQuickItemPrivate::get(rect)->setState("moved"); - - delete rect; + QQuickItemPrivate::get(rect.data())->setState("moved"); } void tst_qquickbehaviors::colorBehavior() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("color.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("red"); + QQuickItemPrivate::get(rect.data())->setState("red"); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->color() != QColor("red")); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->color() != QColor("green")); //i.e. the behavior has been triggered - - delete rect; } void tst_qquickbehaviors::parentBehavior() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("parent.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("reparented"); + QQuickItemPrivate::get(rect.data())->setState("reparented"); QTRY_VERIFY(rect->findChild<QQuickRectangle*>("MyRect")->parentItem() != rect->findChild<QQuickItem*>("NewParent")); QTRY_VERIFY(rect->findChild<QQuickRectangle*>("MyRect")->parentItem() == rect->findChild<QQuickItem*>("NewParent")); - - delete rect; } void tst_qquickbehaviors::replaceBinding() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("binding.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); QTRY_VERIFY(innerRect); QTRY_VERIFY(innerRect->x() > 0); @@ -187,7 +175,7 @@ void tst_qquickbehaviors::replaceBinding() rect->setProperty("movedx", 210); QTRY_COMPARE(innerRect->x(), (qreal)210); - QQuickItemPrivate::get(rect)->setState(""); + QQuickItemPrivate::get(rect.data())->setState(""); QTRY_VERIFY(innerRect->x() > 10); QTRY_VERIFY(innerRect->x() < 210); //i.e. the behavior has been triggered QTRY_COMPARE(innerRect->x(), (qreal)10); @@ -195,8 +183,6 @@ void tst_qquickbehaviors::replaceBinding() QTRY_COMPARE(innerRect->x(), (qreal)10); rect->setProperty("basex", 20); QTRY_COMPARE(innerRect->x(), (qreal)20); - - delete rect; } void tst_qquickbehaviors::group() @@ -205,32 +191,27 @@ void tst_qquickbehaviors::group() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("groupProperty.qml"))); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - qDebug() << c.errorString(); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); //QTest::qWait(200); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() > 0); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() < 200); //i.e. the behavior has been triggered - - delete rect; } */ { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("groupProperty2.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QTRY_VERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->border()->width() > 0); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->border()->width() < 4); //i.e. the behavior has been triggered - - delete rect; } } @@ -238,56 +219,48 @@ void tst_qquickbehaviors::valueType() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("valueType.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); //QTBUG-20827 QCOMPARE(rect->color(), QColor::fromRgb(255,0,255)); - - delete rect; } void tst_qquickbehaviors::emptyBehavior() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("empty.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); qreal x = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x(); QCOMPARE(x, qreal(200)); //should change immediately - - delete rect; } void tst_qquickbehaviors::explicitSelection() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("explicit.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() > 0); QTRY_VERIFY(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x() < 200); //i.e. the behavior has been triggered - - delete rect; } void tst_qquickbehaviors::nonSelectingBehavior() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("nonSelecting2.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); qreal x = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x(); QCOMPARE(x, qreal(200)); //should change immediately - - delete rect; } void tst_qquickbehaviors::reassignedAnimation() @@ -296,27 +269,23 @@ void tst_qquickbehaviors::reassignedAnimation() QQmlComponent c(&engine, testFileUrl("reassignedAnimation.qml")); QString warning = testFileUrl("reassignedAnimation.qml").toString() + ":9:9: QML Behavior: Cannot change the animation assigned to a Behavior."; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QCOMPARE(qobject_cast<QQuickNumberAnimation*>( rect->findChild<QQuickBehavior*>("MyBehavior")->animation())->duration(), 200); - - delete rect; } void tst_qquickbehaviors::disabled() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("disabled.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QCOMPARE(rect->findChild<QQuickBehavior*>("MyBehavior")->enabled(), false); - QQuickItemPrivate::get(rect)->setState("moved"); + QQuickItemPrivate::get(rect.data())->setState("moved"); qreal x = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"))->x(); QCOMPARE(x, qreal(200)); //should change immediately - - delete rect; } void tst_qquickbehaviors::dontStart() @@ -327,13 +296,12 @@ void tst_qquickbehaviors::dontStart() QString warning = c.url().toString() + ":13:13: QML NumberAnimation: setRunning() cannot be used on non-root animation nodes."; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickAbstractAnimation *myAnim = rect->findChild<QQuickAbstractAnimation*>("MyAnim"); - QVERIFY(myAnim && !myAnim->qtAnimation()); - - delete rect; + QVERIFY(myAnim); + QVERIFY(!myAnim->qtAnimation()); } void tst_qquickbehaviors::startup() @@ -341,22 +309,20 @@ void tst_qquickbehaviors::startup() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("startup.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickRectangle *innerRect = rect->findChild<QQuickRectangle*>("innerRect"); QVERIFY(innerRect); QCOMPARE(innerRect->x(), qreal(100)); //should be set immediately - - delete rect; } { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("startup2.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickRectangle *innerRect = rect->findChild<QQuickRectangle*>("innerRect"); QVERIFY(innerRect); @@ -365,8 +331,6 @@ void tst_qquickbehaviors::startup() QVERIFY(text); QCOMPARE(innerRect->x(), text->width()); //should be set immediately - - delete rect; } } @@ -375,10 +339,8 @@ void tst_qquickbehaviors::groupedPropertyCrash() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("groupedPropertyCrash.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); //don't crash - - delete rect; + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); //don't crash } //QTBUG-5491 @@ -386,8 +348,8 @@ void tst_qquickbehaviors::runningTrue() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("runningTrue.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickAbstractAnimation *animation = rect->findChild<QQuickAbstractAnimation*>("rotAnim"); QVERIFY(animation); @@ -395,8 +357,6 @@ void tst_qquickbehaviors::runningTrue() QSignalSpy runningSpy(animation, SIGNAL(runningChanged(bool))); rect->setProperty("myValue", 180); QTRY_VERIFY(runningSpy.count() > 0); - - delete rect; } //QTBUG-12295 @@ -404,8 +364,8 @@ void tst_qquickbehaviors::sameValue() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("qtbug12295.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickRectangle *target = rect->findChild<QQuickRectangle*>("myRect"); QVERIFY(target); @@ -424,8 +384,6 @@ void tst_qquickbehaviors::sameValue() //even though we set 0 twice in a row. target->setProperty("x", 0); QTRY_VERIFY(target->x() != qreal(0) && target->x() != qreal(100)); - - delete rect; } //QTBUG-18362 @@ -434,8 +392,8 @@ void tst_qquickbehaviors::delayedRegistration() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("delayedRegistration.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickItem *innerRect = rect->property("myItem").value<QQuickItem*>(); QVERIFY(innerRect != 0); @@ -451,8 +409,8 @@ void tst_qquickbehaviors::startOnCompleted() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("startOnCompleted.qml")); - QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickItem *innerRect = rect->findChild<QQuickRectangle*>(); QVERIFY(innerRect != 0); @@ -460,8 +418,6 @@ void tst_qquickbehaviors::startOnCompleted() QCOMPARE(innerRect->property("x").toInt(), int(0)); QTRY_COMPARE(innerRect->property("x").toInt(), int(100)); - - delete rect; } //QTBUG-25139 @@ -471,7 +427,7 @@ void tst_qquickbehaviors::multipleChangesToValueType() QQmlComponent c(&engine, testFileUrl("multipleChangesToValueType.qml")); QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle *>(c.create())); - QVERIFY(rect != 0); + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickText *text = rect->findChild<QQuickText *>(); QVERIFY(text != 0); @@ -496,8 +452,8 @@ void tst_qquickbehaviors::currentValue() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("qtbug21549.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(c.create()); - QVERIFY(item); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create())); + QVERIFY2(!item.isNull(), qPrintable(c.errorString())); QQuickRectangle *target = item->findChild<QQuickRectangle*>("myRect"); QVERIFY(target); @@ -516,15 +472,13 @@ void tst_qquickbehaviors::currentValue() target->setProperty("x", 100); QCOMPARE(item->property("behaviorCount").toInt(), 1); QCOMPARE(target->x(), qreal(100)); - - delete item; } { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("qtbug21549-2.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(c.create()); - QVERIFY(item); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create())); + QVERIFY2(!item.isNull(), qPrintable(c.errorString())); QQuickRectangle *target = item->findChild<QQuickRectangle*>("myRect"); QVERIFY(target); @@ -537,9 +491,7 @@ void tst_qquickbehaviors::currentValue() // in the QML (which should be between 50 and 80); QTRY_COMPARE(item->property("animRunning").toBool(), true); QTRY_COMPARE(item->property("animRunning").toBool(), false); - QVERIFY(target->x() > qreal(50) && target->x() < qreal(80)); - - delete item; + QVERIFY2(target->x() > qreal(50) && target->x() < qreal(80), QByteArray::number(target->x())); } } @@ -548,8 +500,8 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("disabledWriteWhileRunning.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(c.create()); - QVERIFY(root); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(c.create())); + QVERIFY2(!root.isNull(), qPrintable(c.errorString())); QQuickRectangle *myRect = qobject_cast<QQuickRectangle*>(root->findChild<QQuickRectangle*>("MyRect")); QQuickBehavior *myBehavior = qobject_cast<QQuickBehavior*>(root->findChild<QQuickBehavior*>("MyBehavior")); @@ -579,16 +531,14 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() QCOMPARE(myRect->x(), qreal(100)); QTest::qWait(200); QCOMPARE(myRect->x(), qreal(100)); - - delete root; } //test additional complications with SmoothedAnimation { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("disabledWriteWhileRunning2.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(c.create()); - QVERIFY(root); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(c.create())); + QVERIFY2(!root.isNull(), qPrintable(c.errorString())); QQuickRectangle *myRect = qobject_cast<QQuickRectangle*>(root->findChild<QQuickRectangle*>("MyRect")); QQuickBehavior *myBehavior = qobject_cast<QQuickBehavior*>(root->findChild<QQuickBehavior*>("MyBehavior")); @@ -623,8 +573,6 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() QCOMPARE(myRect->x(), qreal(100)); QTest::qWait(200); QCOMPARE(myRect->x(), qreal(100)); - - delete root; } } diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index efe2ca8b18..2a96bd1501 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -132,6 +132,13 @@ void tst_qquickborderimage::imageSource() QFETCH(bool, remote); QFETCH(QString, error); +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + if (qstrcmp(QTest::currentDataTag(), "remote") == 0 + || qstrcmp(QTest::currentDataTag(), "remote not found") == 0) { + QSKIP("Remote tests cause occasional hangs in the CI system -- QTBUG-45655"); + } +#endif + TestHTTPServer server; if (remote) { QVERIFY2(server.listen(), qPrintable(server.errorString())); diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST index 92ed8708de..647bf819a5 100644 --- a/tests/auto/quick/qquickflickable/BLACKLIST +++ b/tests/auto/quick/qquickflickable/BLACKLIST @@ -10,7 +10,7 @@ osx-10.10 osx-10.10 [stopAtBounds] osx-10.10 -windows 32bit developer-build +windows developer-build [returnToBounds] osx [pressWhileFlicking] diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 7d08c3c81e..44da9a64e5 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -249,7 +249,7 @@ void tst_qquickflickable::rebound() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -295,11 +295,11 @@ void tst_qquickflickable::rebound() // flick and trigger the transition multiple times // (moving signals are emitted as soon as the first transition starts) - flick(window.data(), QPoint(20,20), QPoint(120,120), 200); // both x and y will bounce back - flick(window.data(), QPoint(20,120), QPoint(120,20), 200); // only x will bounce back + flick(window.data(), QPoint(20,20), QPoint(120,120), 50); // both x and y will bounce back + flick(window.data(), QPoint(20,120), QPoint(120,20), 50); // only x will bounce back QVERIFY(flickable->isMoving()); - QVERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1); + QTRY_VERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1); QCOMPARE(hMoveSpy.count(), 1); QCOMPARE(vMoveSpy.count(), 1); QCOMPARE(movementStartedSpy.count(), 1); @@ -388,7 +388,7 @@ void tst_qquickflickable::pressDelay() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -406,7 +406,7 @@ void tst_qquickflickable::pressDelay() QQuickItem *mouseArea = window->rootObject()->findChild<QQuickItem*>("mouseArea"); QSignalSpy clickedSpy(mouseArea, SIGNAL(clicked(QQuickMouseEvent*))); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + moveAndPress(window.data(), QPoint(150, 150)); // The press should not occur immediately QVERIFY(mouseArea->property("pressed").toBool() == false); @@ -427,7 +427,7 @@ void tst_qquickflickable::pressDelay() // Test a quick tap within the pressDelay timeout clickedSpy.clear(); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(180, 180)); + moveAndPress(window.data(), QPoint(180, 180)); // The press should not occur immediately QVERIFY(mouseArea->property("pressed").toBool() == false); @@ -444,7 +444,7 @@ void tst_qquickflickable::pressDelay() // QTBUG-31168 - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 110)); + moveAndPress(window.data(), QPoint(150, 110)); // The press should not occur immediately QVERIFY(mouseArea->property("pressed").toBool() == false); @@ -469,7 +469,7 @@ void tst_qquickflickable::nestedPressDelay() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -478,7 +478,7 @@ void tst_qquickflickable::nestedPressDelay() QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); QVERIFY(inner != 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + moveAndPress(window.data(), QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); QVERIFY(inner->property("pressed").toBool() == false); @@ -490,7 +490,7 @@ void tst_qquickflickable::nestedPressDelay() QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); // Dragging inner Flickable should work - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(80, 150)); + moveAndPress(window.data(), QPoint(80, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); QVERIFY(inner->property("pressed").toBool() == false); @@ -505,7 +505,7 @@ void tst_qquickflickable::nestedPressDelay() QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(20, 150)); // Dragging the MouseArea in the inner Flickable should move the inner Flickable - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + moveAndPress(window.data(), QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); @@ -529,7 +529,7 @@ void tst_qquickflickable::nestedClickThenFlick() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -538,7 +538,7 @@ void tst_qquickflickable::nestedClickThenFlick() QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); QVERIFY(inner != 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + moveAndPress(window.data(), QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); @@ -549,7 +549,7 @@ void tst_qquickflickable::nestedClickThenFlick() QVERIFY(outer->property("pressed").toBool() == false); // Dragging inner Flickable should work - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(80, 150)); + moveAndPress(window.data(), QPoint(80, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); @@ -628,6 +628,8 @@ void tst_qquickflickable::returnToBounds() window->rootContext()->setContextProperty("setRebound", setRebound); window->setSource(testFileUrl("resize.qml")); + window->show(); + QTest::qWaitForWindowActive(window.data()); QVERIFY(window->rootObject() != 0); QQuickFlickable *obj = findItem<QQuickFlickable>(window->rootObject(), "flick"); @@ -671,7 +673,7 @@ void tst_qquickflickable::wheel() QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("wheel.qml")); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flick"); @@ -740,7 +742,7 @@ void tst_qquickflickable::movingAndFlicking() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -903,7 +905,7 @@ void tst_qquickflickable::movingAndDragging() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -922,7 +924,7 @@ void tst_qquickflickable::movingAndDragging() QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded())); // start the drag - QTest::mousePress(window.data(), Qt::LeftButton, 0, moveFrom); + moveAndPress(window.data(), moveFrom); QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack); QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack*2); QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack*3); @@ -998,7 +1000,7 @@ void tst_qquickflickable::movingAndDragging() flickable->setContentX(0); flickable->setContentY(0); QTRY_VERIFY(!flickable->isMoving()); - QTest::mousePress(window.data(), Qt::LeftButton, 0, moveFrom); + moveAndPress(window.data(), moveFrom); QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack); QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack*2); QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack*3); @@ -1072,7 +1074,7 @@ void tst_qquickflickable::flickOnRelease() QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("flickable03.qml")); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -1085,7 +1087,7 @@ void tst_qquickflickable::flickOnRelease() // underlying drivers will hopefully provide a pre-calculated velocity // (based on more data than what the UI gets), thus making this use case // working even with small movements. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(50, 300)); + moveAndPress(window.data(), QPoint(50, 300)); QTest::mouseMove(window.data(), QPoint(50, 10), 10); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 10), 10); @@ -1109,7 +1111,7 @@ void tst_qquickflickable::pressWhileFlicking() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -1159,13 +1161,13 @@ void tst_qquickflickable::disabled() QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("disabled.qml")); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flickable"); QVERIFY(flick != 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(50, 90)); + moveAndPress(window.data(), QPoint(50, 90)); QTest::mouseMove(window.data(), QPoint(50, 80)); QTest::mouseMove(window.data(), QPoint(50, 70)); @@ -1176,7 +1178,7 @@ void tst_qquickflickable::disabled() QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 60)); // verify that mouse clicks on other elements still work (QTBUG-20584) - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(50, 10)); + moveAndPress(window.data(), QPoint(50, 10)); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 10)); QTRY_VERIFY(window->rootObject()->property("clicked").toBool() == true); @@ -1190,7 +1192,7 @@ void tst_qquickflickable::flickVelocity() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); @@ -1235,7 +1237,7 @@ void tst_qquickflickable::margins() QQuickViewTestUtil::moveMouseAway(window.data()); window->setTitle(QTest::currentTestFunction()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickItem *root = window->rootObject(); QVERIFY(root); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); @@ -1298,13 +1300,13 @@ void tst_qquickflickable::cancelOnMouseGrab() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); QVERIFY(flickable != 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10, 10)); + moveAndPress(window.data(), QPoint(10, 10)); // drag out of bounds QTest::mouseMove(window.data(), QPoint(50, 50)); QTest::mouseMove(window.data(), QPoint(100, 100)); @@ -1324,7 +1326,7 @@ void tst_qquickflickable::cancelOnMouseGrab() QTRY_VERIFY(!flickable->isMoving()); QTRY_VERIFY(!flickable->isDragging()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 10)); + moveAndRelease(window.data(), QPoint(50, 10)); } @@ -1336,41 +1338,41 @@ void tst_qquickflickable::clickAndDragWhenTransformed() QQuickViewTestUtil::centerOnScreen(view.data()); QQuickViewTestUtil::moveMouseAway(view.data()); view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view.data())); + QVERIFY(QTest::qWaitForWindowActive(view.data())); QVERIFY(view->rootObject() != 0); QQuickFlickable *flickable = view->rootObject()->findChild<QQuickFlickable*>("flickable"); QVERIFY(flickable != 0); // click outside child rect - QTest::mousePress(view.data(), Qt::LeftButton, 0, QPoint(190, 190)); + moveAndPress(view.data(), QPoint(190, 190)); QTRY_COMPARE(flickable->property("itemPressed").toBool(), false); QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(190, 190)); // click inside child rect - QTest::mousePress(view.data(), Qt::LeftButton, 0, QPoint(200, 200)); + moveAndPress(view.data(), QPoint(200, 200)); QTRY_COMPARE(flickable->property("itemPressed").toBool(), true); QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(200, 200)); const int threshold = qApp->styleHints()->startDragDistance(); // drag outside bounds - QTest::mousePress(view.data(), Qt::LeftButton, 0, QPoint(160, 160)); + moveAndPress(view.data(), QPoint(160, 160)); QTest::qWait(10); QTest::mouseMove(view.data(), QPoint(160 + threshold * 2, 160)); QTest::mouseMove(view.data(), QPoint(160 + threshold * 3, 160)); QCOMPARE(flickable->isDragging(), false); QCOMPARE(flickable->property("itemPressed").toBool(), false); - QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(180, 160)); + moveAndRelease(view.data(), QPoint(180, 160)); // drag inside bounds - QTest::mousePress(view.data(), Qt::LeftButton, 0, QPoint(200, 140)); + moveAndPress(view.data(), QPoint(200, 140)); QTest::qWait(10); QTest::mouseMove(view.data(), QPoint(200 + threshold * 2, 140)); QTest::mouseMove(view.data(), QPoint(200 + threshold * 3, 140)); QCOMPARE(flickable->isDragging(), true); QCOMPARE(flickable->property("itemPressed").toBool(), false); - QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(220, 140)); + moveAndRelease(view.data(), QPoint(220, 140)); } void tst_qquickflickable::flickTwiceUsingTouches() @@ -1459,7 +1461,7 @@ void tst_qquickflickable::nestedStopAtBounds() QQuickViewTestUtil::moveMouseAway(&view); view.show(); view.requestActivate(); - QVERIFY(QTest::qWaitForWindowExposed(&view)); + QVERIFY(QTest::qWaitForWindowActive(&view)); QVERIFY(view.rootObject()); QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(view.rootObject()); @@ -1489,7 +1491,7 @@ void tst_qquickflickable::nestedStopAtBounds() int &axis = transpose ? position.ry() : position.rx(); // drag toward the aligned boundary. Outer flickable dragged. - QTest::mousePress(&view, Qt::LeftButton, 0, position); + moveAndPress(&view, position); QTest::qWait(10); axis += invert ? threshold * 2 : -threshold * 2; QTest::mouseMove(&view, position); @@ -1507,7 +1509,7 @@ void tst_qquickflickable::nestedStopAtBounds() outer->setContentY(50); // drag away from the aligned boundary. Inner flickable dragged. - QTest::mousePress(&view, Qt::LeftButton, 0, position); + moveAndPress(&view, position); QTest::qWait(10); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); @@ -1526,7 +1528,7 @@ void tst_qquickflickable::nestedStopAtBounds() inner->setContentHeight(inner->height() - margin); // Drag inner with equal size and contentSize - QTest::mousePress(&view, Qt::LeftButton, 0, position); + moveAndPress(&view, position); QTest::qWait(10); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); @@ -1543,7 +1545,7 @@ void tst_qquickflickable::nestedStopAtBounds() inner->setContentHeight(inner->height() - 100); // Drag inner with size greater than contentSize - QTest::mousePress(&view, Qt::LeftButton, 0, position); + moveAndPress(&view, position); QTest::qWait(10); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); @@ -1583,7 +1585,7 @@ void tst_qquickflickable::stopAtBounds() QQuickViewTestUtil::moveMouseAway(&view); view.show(); view.requestActivate(); - QVERIFY(QTest::qWaitForWindowExposed(&view)); + QVERIFY(QTest::qWaitForWindowActive(&view)); QVERIFY(view.rootObject()); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(view.rootObject()); @@ -1601,7 +1603,7 @@ void tst_qquickflickable::stopAtBounds() int &axis = transpose ? position.ry() : position.rx(); // drag away from the aligned boundary. View should not move - QTest::mousePress(&view, Qt::LeftButton, 0, position); + moveAndPress(&view, position); QTest::qWait(10); for (int i = 0; i < 3; ++i) { axis += invert ? -threshold : threshold; @@ -1649,12 +1651,14 @@ void tst_qquickflickable::stopAtBounds() } else { flickable->setContentX(invert ? 100 : 0); } + + QSignalSpy flickSignal(flickable, SIGNAL(flickingChanged())); if (invert) flick(&view, QPoint(20,20), QPoint(120,120), 100); else flick(&view, QPoint(120,120), QPoint(20,20), 100); - QVERIFY(flickable->isFlicking()); + QVERIFY(flickSignal.count() > 0); if (transpose) { if (invert) QTRY_COMPARE(flickable->isAtYBeginning(), true); @@ -1707,11 +1711,11 @@ void tst_qquickflickable::pressDelayWithLoader() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QVERIFY(window->rootObject() != 0); // do not crash - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + moveAndPress(window.data(), QPoint(150, 150)); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); } diff --git a/tests/auto/quick/qquickgridview/BLACKLIST b/tests/auto/quick/qquickgridview/BLACKLIST new file mode 100644 index 0000000000..9eb9940aa5 --- /dev/null +++ b/tests/auto/quick/qquickgridview/BLACKLIST @@ -0,0 +1,2 @@ +[snapOneRow:horizontal, right to left] +windows diff --git a/tests/auto/quick/qquickgridview/data/contentHeightWithDelayRemove.qml b/tests/auto/quick/qquickgridview/data/contentHeightWithDelayRemove.qml new file mode 100644 index 0000000000..3f8246bafc --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/contentHeightWithDelayRemove.qml @@ -0,0 +1,47 @@ +import QtQuick 2.1 + +Item { + width: 400 + height: 600 + function takeOne() + { + gridView.model.remove(2) + } + function takeThree() + { + gridView.model.remove(4) + gridView.model.remove(2) + gridView.model.remove(0) + } + function takeAll() + { + gridView.model.clear() + } + + GridView { + id: gridView + + property bool useDelayRemove + + height: parent.height + width: 400 + cellWidth: width/2 + model: ListModel { + ListElement { name: "A" } + ListElement { name: "B" } + ListElement { name: "C" } + ListElement { name: "D" } + ListElement { name: "E" } + } + delegate: Text { + id: wrapper + height: 100 + text: index + gridView.count + GridView.delayRemove: gridView.useDelayRemove + GridView.onRemove: SequentialAnimation { + PauseAnimation { duration: wrapper.GridView.delayRemove ? 100 : 0 } + PropertyAction { target: wrapper; property: "GridView.delayRemove"; value: false } + } + } + } +} diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 9472407e01..d53ee00b45 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -206,6 +206,9 @@ private slots: void jsArrayChange(); + void contentHeightWithDelayRemove_data(); + void contentHeightWithDelayRemove(); + private: QList<int> toIntList(const QVariantList &list); void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes); @@ -4315,8 +4318,19 @@ void tst_QQuickGridView::snapToRow() QQuickItem *contentItem = gridview->contentItem(); QTRY_VERIFY(contentItem != 0); + qreal origContentY = gridview->contentY(); + qreal origContentX = gridview->contentX(); // confirm that a flick hits an item boundary flick(window, flickStart, flickEnd, 180); + + // wait until it's at least one cell further + QTRY_VERIFY(qAbs(gridview->contentX() - origContentX) > 80 || + qAbs(gridview->contentY() - origContentY) > 80); + + // click to stop it. Otherwise we wouldn't know how much further it will go. We don't want to it + // to hit the endExtent, yet. + QTest::mouseClick(window, Qt::LeftButton, 0, flickEnd); + QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment); @@ -6460,6 +6474,74 @@ void tst_QQuickGridView::jsArrayChange() QCOMPARE(spy.count(), 1); } +void tst_QQuickGridView::contentHeightWithDelayRemove_data() +{ + QTest::addColumn<bool>("useDelayRemove"); + QTest::addColumn<QByteArray>("removeFunc"); + QTest::addColumn<int>("countDelta"); + QTest::addColumn<qreal>("contentHeightDelta"); + + QTest::newRow("remove without delayRemove") + << false + << QByteArray("takeOne") + << -1 + << qreal(-1 * 100.0); + + QTest::newRow("remove with delayRemove") + << true + << QByteArray("takeOne") + << -1 + << qreal(-1 * 100.0); + + QTest::newRow("remove with multiple delayRemove") + << true + << QByteArray("takeThree") + << -3 + << qreal(-2 * 100.0); + + QTest::newRow("clear with delayRemove") + << true + << QByteArray("takeAll") + << -5 + << qreal(-3 * 100.0); +} + +void tst_QQuickGridView::contentHeightWithDelayRemove() +{ + QFETCH(bool, useDelayRemove); + QFETCH(QByteArray, removeFunc); + QFETCH(int, countDelta); + QFETCH(qreal, contentHeightDelta); + + QQuickView *window = createView(); + window->setSource(testFileUrl("contentHeightWithDelayRemove.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickGridView *gridview = window->rootObject()->findChild<QQuickGridView*>(); + QTRY_VERIFY(gridview != 0); + + const int initialCount(gridview->count()); + const int eventualCount(initialCount + countDelta); + + const qreal initialContentHeight(gridview->contentHeight()); + const int eventualContentHeight(qRound(initialContentHeight + contentHeightDelta)); + + gridview->setProperty("useDelayRemove", useDelayRemove); + QMetaObject::invokeMethod(window->rootObject(), removeFunc.constData()); + QTest::qWait(50); + QCOMPARE(gridview->count(), eventualCount); + + if (useDelayRemove) { + QCOMPARE(qRound(gridview->contentHeight()), qRound(initialContentHeight)); + QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); + } else { + QCOMPARE(qRound(gridview->contentHeight()), eventualContentHeight); + } + + delete window; +} + QTEST_MAIN(tst_QQuickGridView) #include "tst_qquickgridview.moc" diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index ce8b52222d..91ef921141 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -168,6 +168,18 @@ void tst_qquickimage::imageSource() QFETCH(bool, cache); QFETCH(QString, error); + +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + if (qstrcmp(QTest::currentDataTag(), "remote") == 0 + || qstrcmp(QTest::currentDataTag(), "remote redirected") == 0 + || qstrcmp(QTest::currentDataTag(), "remote svg") == 0 + || qstrcmp(QTest::currentDataTag(), "remote svgz") == 0 + || qstrcmp(QTest::currentDataTag(), "remote not found") == 0 + ) { + QSKIP("Remote tests cause occasional hangs in the CI system -- QTBUG-45655"); + } +#endif + TestHTTPServer server; if (remote) { QVERIFY2(server.listen(), qPrintable(server.errorString())); @@ -554,16 +566,17 @@ void tst_qquickimage::noLoading() QTRY_VERIFY(obj->status() == QQuickImage::Ready); QTRY_VERIFY(obj->progress() == 1.0); QTRY_COMPARE(sourceSpy.count(), 2); - QTRY_COMPARE(progressSpy.count(), 2); + QTRY_VERIFY(progressSpy.count() >= 2); QTRY_COMPARE(statusSpy.count(), 3); // Loading remote file again - should not go through 'Loading' state. + progressSpy.clear(); ctxt->setContextProperty("srcImage", testFileUrl("green.png")); ctxt->setContextProperty("srcImage", server.url("/rect.png")); QTRY_VERIFY(obj->status() == QQuickImage::Ready); QTRY_VERIFY(obj->progress() == 1.0); QTRY_COMPARE(sourceSpy.count(), 4); - QTRY_COMPARE(progressSpy.count(), 2); + QTRY_COMPARE(progressSpy.count(), 0); QTRY_COMPARE(statusSpy.count(), 5); delete obj; diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp index dae46b5c3d..80406be753 100644 --- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp +++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp @@ -37,6 +37,7 @@ #include <private/qquickimage_p.h> #include <QImageReader> #include <QWaitCondition> +#include <QThreadPool> Q_DECLARE_METATYPE(QQuickImageProvider*); @@ -68,6 +69,8 @@ private slots: void threadTest(); + void asyncTextureTest(); + private: QString newImageFileName() const; void fillRequestTestsData(const QString &id); @@ -457,6 +460,101 @@ void tst_qquickimageprovider::threadTest() } } +class TestImageResponse : public QQuickImageResponse, public QRunnable +{ + public: + TestImageResponse(QMutex *lock, QWaitCondition *condition, bool *ok, const QString &id, const QSize &requestedSize) + : m_lock(lock), m_condition(condition), m_ok(ok), m_id(id), m_requestedSize(requestedSize), m_texture(0) + { + setAutoDelete(false); + } + + QQuickTextureFactory *textureFactory() const + { + return m_texture; + } + + void run() + { + m_lock->lock(); + if (!(*m_ok)) { + m_condition->wait(m_lock); + } + m_lock->unlock(); + QImage image(50, 50, QImage::Format_RGB32); + image.fill(QColor(m_id).rgb()); + if (m_requestedSize.isValid()) + image = image.scaled(m_requestedSize); + m_texture = QQuickTextureFactory::textureFactoryForImage(image); + emit finished(); + } + + QMutex *m_lock; + QWaitCondition *m_condition; + bool *m_ok; + QString m_id; + QSize m_requestedSize; + QQuickTextureFactory *m_texture; +}; + +class TestAsyncProvider : public QQuickAsyncImageProvider +{ + public: + TestAsyncProvider() : ok(false) + { + pool.setMaxThreadCount(4); + } + + ~TestAsyncProvider() {} + + QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) + { + TestImageResponse *response = new TestImageResponse(&lock, &condition, &ok, id, requestedSize); + pool.start(response); + return response; + } + + QThreadPool pool; + QMutex lock; + QWaitCondition condition; + bool ok; +}; + + +void tst_qquickimageprovider::asyncTextureTest() +{ + QQmlEngine engine; + + TestAsyncProvider *provider = new TestAsyncProvider; + + engine.addImageProvider("test_async", provider); + QVERIFY(engine.imageProvider("test_async") != 0); + + QString componentStr = "import QtQuick 2.0\nItem { \n" + "Image { source: \"image://test_async/blue\"; }\n" + "Image { source: \"image://test_async/red\"; }\n" + "Image { source: \"image://test_async/green\"; }\n" + "Image { source: \"image://test_async/yellow\"; }\n" + " }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QObject *obj = component.create(); + //MUST not deadlock + QVERIFY(obj != 0); + QList<QQuickImage *> images = obj->findChildren<QQuickImage *>(); + QCOMPARE(images.count(), 4); + + QTRY_VERIFY(provider->pool.activeThreadCount() == 4); + foreach (QQuickImage *img, images) { + QTRY_VERIFY(img->status() == QQuickImage::Loading); + } + provider->ok = true; + provider->condition.wakeAll(); + foreach (QQuickImage *img, images) { + QTRY_VERIFY(img->status() == QQuickImage::Ready); + } +} + QTEST_MAIN(tst_qquickimageprovider) diff --git a/tests/auto/quick/qquickitem/BLACKLIST b/tests/auto/quick/qquickitem/BLACKLIST new file mode 100644 index 0000000000..d94a3ef102 --- /dev/null +++ b/tests/auto/quick/qquickitem/BLACKLIST @@ -0,0 +1,2 @@ +[contains:hollow square: testing points inside] +xcb diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST new file mode 100644 index 0000000000..269696ce8c --- /dev/null +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -0,0 +1,4 @@ +[QTBUG_38209] +* +[enforceRange_withoutHighlight] +osx diff --git a/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml b/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml new file mode 100644 index 0000000000..06011519b2 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml @@ -0,0 +1,46 @@ +import QtQuick 2.1 + +Item { + width: 400 + height: 600 + function takeOne() + { + listView.model.remove(2) + } + function takeThree() + { + listView.model.remove(4) + listView.model.remove(2) + listView.model.remove(0) + } + function takeAll() + { + listView.model.clear() + } + + ListView { + id: listView + + property bool useDelayRemove + + height: parent.height + width: 400 + model: ListModel { + ListElement { name: "A" } + ListElement { name: "B" } + ListElement { name: "C" } + ListElement { name: "D" } + ListElement { name: "E" } + } + delegate: Text { + id: wrapper + height: 100 + text: index + listView.count + ListView.delayRemove: listView.useDelayRemove + ListView.onRemove: SequentialAnimation { + PauseAnimation { duration: wrapper.ListView.delayRemove ? 100 : 0 } + PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false } + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/objectmodel.qml b/tests/auto/quick/qquicklistview/data/objectmodel.qml new file mode 100644 index 0000000000..5c23d64cd3 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/objectmodel.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 +import QtQml.Models 2.1 + +ListView { + width: 360 + height: 360 + model: ObjectModel { + Rectangle { + width: 20 + height: 20 + color: "red" + } + Rectangle { + width: 20 + height: 20 + color: "green" + } + Rectangle { + width: 20 + height: 20 + color: "blue" + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index c93aac456d..6377650696 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -241,6 +241,10 @@ private slots: void QTBUG_39492(); void jsArrayChange(); + void objectModel(); + + void contentHeightWithDelayRemove(); + void contentHeightWithDelayRemove_data(); private: template <class T> void items(const QUrl &source); @@ -8063,6 +8067,135 @@ void tst_QQuickListView::jsArrayChange() QCOMPARE(spy.count(), 1); } +static bool compareObjectModel(QQuickListView *listview, QQmlObjectModel *model) +{ + if (listview->count() != model->count()) + return false; + for (int i = 0; i < listview->count(); ++i) { + listview->setCurrentIndex(i); + if (listview->currentItem() != model->get(i)) + return false; + } + return true; +} + +void tst_QQuickListView::objectModel() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("objectmodel.qml")); + + QQuickListView *listview = qobject_cast<QQuickListView *>(component.create()); + QVERIFY(listview); + + QQmlObjectModel *model = listview->model().value<QQmlObjectModel *>(); + QVERIFY(model); + + listview->setCurrentIndex(0); + QVERIFY(listview->currentItem()); + QCOMPARE(listview->currentItem()->property("color").toString(), QColor("red").name()); + + listview->setCurrentIndex(1); + QVERIFY(listview->currentItem()); + QCOMPARE(listview->currentItem()->property("color").toString(), QColor("green").name()); + + listview->setCurrentIndex(2); + QVERIFY(listview->currentItem()); + QCOMPARE(listview->currentItem()->property("color").toString(), QColor("blue").name()); + + QQuickItem *item0 = new QQuickItem(listview); + item0->setSize(QSizeF(20, 20)); + model->append(item0); + QCOMPARE(model->count(), 4); + QVERIFY(compareObjectModel(listview, model)); + + QQuickItem *item1 = new QQuickItem(listview); + item1->setSize(QSizeF(20, 20)); + model->insert(0, item1); + QCOMPARE(model->count(), 5); + QVERIFY(compareObjectModel(listview, model)); + + model->move(1, 2, 3); + QVERIFY(compareObjectModel(listview, model)); + + model->remove(2, 2); + QCOMPARE(model->count(), 3); + QVERIFY(compareObjectModel(listview, model)); + + model->clear(); + QCOMPARE(model->count(), 0); + QCOMPARE(listview->count(), 0); + + delete listview; +} + +void tst_QQuickListView::contentHeightWithDelayRemove_data() +{ + QTest::addColumn<bool>("useDelayRemove"); + QTest::addColumn<QByteArray>("removeFunc"); + QTest::addColumn<int>("countDelta"); + QTest::addColumn<qreal>("contentHeightDelta"); + + QTest::newRow("remove without delayRemove") + << false + << QByteArray("takeOne") + << -1 + << qreal(-1 * 100.0); + + QTest::newRow("remove with delayRemove") + << true + << QByteArray("takeOne") + << -1 + << qreal(-1 * 100.0); + + QTest::newRow("remove with multiple delayRemove") + << true + << QByteArray("takeThree") + << -3 + << qreal(-3 * 100.0); + + QTest::newRow("clear with delayRemove") + << true + << QByteArray("takeAll") + << -5 + << qreal(-5 * 100.0); +} + +void tst_QQuickListView::contentHeightWithDelayRemove() +{ + QFETCH(bool, useDelayRemove); + QFETCH(QByteArray, removeFunc); + QFETCH(int, countDelta); + QFETCH(qreal, contentHeightDelta); + + QQuickView *window = createView(); + window->setSource(testFileUrl("contentHeightWithDelayRemove.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); + QTRY_VERIFY(listview != 0); + + const int initialCount(listview->count()); + const int eventualCount(initialCount + countDelta); + + const qreal initialContentHeight(listview->contentHeight()); + const int eventualContentHeight(qRound(initialContentHeight + contentHeightDelta)); + + listview->setProperty("useDelayRemove", useDelayRemove); + QMetaObject::invokeMethod(window->rootObject(), removeFunc.constData()); + QTest::qWait(50); + QCOMPARE(listview->count(), eventualCount); + + if (useDelayRemove) { + QCOMPARE(qRound(listview->contentHeight()), qRound(initialContentHeight)); + QTRY_COMPARE(qRound(listview->contentHeight()), eventualContentHeight); + } else { + QCOMPARE(qRound(listview->contentHeight()), eventualContentHeight); + } + + delete window; +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST new file mode 100644 index 0000000000..1777af9e0c --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST @@ -0,0 +1,2 @@ +[inFlickable] +* diff --git a/tests/auto/quick/qquickpathview/data/customAttribute.qml b/tests/auto/quick/qquickpathview/data/customAttribute.qml new file mode 100644 index 0000000000..bd4c9fd1de --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/customAttribute.qml @@ -0,0 +1,58 @@ +import QtQuick 2.4 + +PathView { + width: 200 + height: 600 + + pathItemCount: 7 + + model: ListModel { + ListElement { color: "salmon" } + ListElement { color: "seagreen" } + ListElement { color: "navy" } + ListElement { color: "goldenrod" } + } + path: Path { + startX: width / 2; startY: -100 + PathAttribute { name: "BEGIN" } + + PathLine { relativeX: 0; y: height / 2 } + PathAttribute { name: "BEGIN" } + + PathLine { relativeX: 0; y: height + 100 } + PathAttribute { name: "BEGIN" } + } + delegate: Rectangle { + width: 200 + height: 200 + color: model.color + opacity: PathView.transparency + } + + Component { + id: attributeComponent + PathAttribute {} + } + + function addAttribute(name, values) { + var valueIndex = 0 + var elements = [] + for (var i = 0; i < path.pathElements.length; ++i) { + elements.push(path.pathElements[i]) + + if (path.pathElements[i].name === "BEGIN") { + if (values[valueIndex] !== undefined) { + var attribute = attributeComponent.createObject(this, { "name": name, "value": values[valueIndex] }) + elements.push(attribute) + } + ++valueIndex + } + } + + console.log("??") + path.pathElements = elements + console.log("!!") + } + + Component.onCompleted: addAttribute("transparency", [0, 1, 0]) +} diff --git a/tests/auto/quick/qquickpathview/data/qtbug42716.qml b/tests/auto/quick/qquickpathview/data/qtbug42716.qml new file mode 100644 index 0000000000..81d52d5ea3 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/qtbug42716.qml @@ -0,0 +1,111 @@ +import QtQuick 2.0 + +Rectangle { + //Note that this file was originally the manual reproduction, MouseAreas were left in. + id: qmlBrowser + + width: 500 + height: 350 + + ListModel { + id: myModel + ListElement { + name: "Bill Jones 0" + } + ListElement { + name: "Jane Doe 1" + } + ListElement { + name: "John Smith 2" + } + ListElement { + name: "Bill Jones 3" + } + ListElement { + name: "Jane Doe 4" + } + ListElement { + name: "John Smith 5" + } + ListElement { + name: "John Smith 6" + } + ListElement { + name: "John Smith 7" + } + } + + Component { + id: delegate + + Text { + id: nameText + height: 33 + width: parent.width + objectName: "delegate"+index + + text: "index: " + index + " text: " + name + font.pointSize: 16 + color: PathView.isCurrentItem ? "red" : "black" + } + } + + PathView { + id: contentList + objectName: "pathView" + anchors.fill: parent + + property int maxPathItemCount: 7 + property real itemHeight: 34 + + delegate: delegate + model: myModel + currentIndex: 5 + pathItemCount: maxPathItemCount + highlightMoveDuration: 0 + + path: Path { + startX: 30 + contentList.width / 2 + startY: 30 + PathLine { + relativeX: 0 + relativeY: contentList.itemHeight * contentList.maxPathItemCount + } + } + + focus: true + Keys.onLeftPressed: decrementCurrentIndex() + Keys.onRightPressed: incrementCurrentIndex() + } + + Column { + anchors.right: parent.right + Text { + text: "Go 1" + font.weight: Font.Bold + font.pixelSize: 24 + MouseArea { + anchors.fill: parent + onClicked: contentList.offset = 2.55882 + } + } + Text { + text: "Go 2" + font.weight: Font.Bold + font.pixelSize: 24 + MouseArea { + anchors.fill: parent + onClicked: contentList.offset = 0.0882353 + } + } + Text { + text: "Go 3" + font.weight: Font.Bold + font.pixelSize: 24 + MouseArea { + anchors.fill: parent + onClicked: contentList.offset = 0.99987 + } + } + } +} diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 7db15522b5..5636b312af 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -140,6 +140,8 @@ private slots: void nestedinFlickable(); void flickableDelegate(); void jsArrayChange(); + void qtbug42716(); + void addCustomAttribute(); }; class TestObject : public QObject @@ -2322,6 +2324,61 @@ void tst_QQuickPathView::jsArrayChange() QCOMPARE(spy.count(), 1); } +/* This bug was one where if you jump the list such that the sole missing item needed to be + * added in the middle of the list, it would instead move an item somewhere else in the list + * to the middle (messing it up very badly). + * + * The test checks correct visual order both before and after the jump. + */ +void tst_QQuickPathView::qtbug42716() +{ + QScopedPointer<QQuickView> window(createView()); + + window->setSource(testFileUrl("qtbug42716.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QCOMPARE(window.data(), qGuiApp->focusWindow()); + + QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView"); + QVERIFY(pathView != 0); + + int order1[] = {5,6,7,0,1,2,3}; + int missing1 = 4; + int order2[] = {0,1,2,3,4,5,6}; + int missing2 = 7; + + qreal lastY = 0.0; + for (int i = 0; i<7; i++) { + QQuickItem *item = findItem<QQuickItem>(pathView, QString("delegate%1").arg(order1[i])); + QVERIFY(item); + QVERIFY(item->y() > lastY); + lastY = item->y(); + } + QQuickItem *itemMiss = findItem<QQuickItem>(pathView, QString("delegate%1").arg(missing1)); + QVERIFY(!itemMiss); + + pathView->setOffset(0.0882353); + //Note refill is delayed, needs time to take effect + QTest::qWait(100); + + lastY = 0.0; + for (int i = 0; i<7; i++) { + QQuickItem *item = findItem<QQuickItem>(pathView, QString("delegate%1").arg(order2[i])); + QVERIFY(item); + QVERIFY(item->y() > lastY); + lastY = item->y(); + } + itemMiss = findItem<QQuickItem>(pathView, QString("delegate%1").arg(missing2)); + QVERIFY(!itemMiss); +} + +void tst_QQuickPathView::addCustomAttribute() +{ + const QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("customAttribute.qml")); + window->show(); +} + QTEST_MAIN(tst_QQuickPathView) #include "tst_qquickpathview.moc" diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp index b9f93a4dcf..584cb78d3d 100644 --- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp +++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp @@ -110,12 +110,14 @@ void tst_qquickpixmapcache::initTestCase() QVERIFY2(server.listen(), qPrintable(server.errorString())); +#ifndef QT_NO_BEARERMANAGEMENT // This avoids a race condition/deadlock bug in network config // manager when it is accessed by the HTTP server thread before // anything else. Bug report can be found at: // QTBUG-26355 QNetworkConfigurationManager cm; cm.updateConfigurations(); +#endif server.serveDirectory(testFile("http")); } diff --git a/tests/auto/quick/qquickpositioners/data/allInvisible.qml b/tests/auto/quick/qquickpositioners/data/allInvisible.qml index 5894171434..3b95a5e1da 100644 --- a/tests/auto/quick/qquickpositioners/data/allInvisible.qml +++ b/tests/auto/quick/qquickpositioners/data/allInvisible.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.6 Item{ width: 400 @@ -41,4 +41,42 @@ Item{ visible: false } } + Grid{ + spacing: 20 + objectName: "grid" + Item{ + width: 0 + height: 20 + visible: false + } + Item{ + width: 20 + height: 0 + visible: false + } + Item{ + width: 20 + height: 20 + visible: false + } + } + Flow{ + spacing: 20 + objectName: "flow" + Item{ + width: 0 + height: 20 + visible: false + } + Item{ + width: 20 + height: 0 + visible: false + } + Item{ + width: 20 + height: 20 + visible: false + } + } } diff --git a/tests/auto/quick/qquickpositioners/data/flowtest-padding.qml b/tests/auto/quick/qquickpositioners/data/flowtest-padding.qml new file mode 100644 index 0000000000..a85e7a5c52 --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/flowtest-padding.qml @@ -0,0 +1,44 @@ +import QtQuick 2.6 + +Item { + width: 90 + height: 480 + property bool testRightToLeft: false + + Flow { + objectName: "flow" + width: parent.width + layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight + padding: 1; topPadding: 2; leftPadding: 3; rightPadding: 4; bottomPadding: 5 + Rectangle { + objectName: "one" + color: "red" + width: 50 + height: 50 + } + Rectangle { + objectName: "two" + color: "green" + width: 20 + height: 50 + } + Rectangle { + objectName: "three" + color: "blue" + width: 50 + height: 20 + } + Rectangle { + objectName: "four" + color: "cyan" + width: 50 + height: 50 + } + Rectangle { + objectName: "five" + color: "magenta" + width: 10 + height: 10 + } + } +} diff --git a/tests/auto/quick/qquickpositioners/data/gridtest-padding.qml b/tests/auto/quick/qquickpositioners/data/gridtest-padding.qml new file mode 100644 index 0000000000..46244ecef5 --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/gridtest-padding.qml @@ -0,0 +1,47 @@ +import QtQuick 2.6 + +Item { + width: 640 + height: 480 + property bool testRightToLeft: false + property int testHAlignment: Grid.AlignLeft; + property int testVAlignment: Grid.AlignTop; + Grid { + layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight + horizontalItemAlignment: testHAlignment + verticalItemAlignment: testVAlignment + objectName: "grid" + columns: 3 + padding: 1; topPadding: 1; leftPadding: 1; rightPadding: 1; bottomPadding: 1 + Rectangle { + objectName: "one" + color: "red" + width: 50 + height: 50 + } + Rectangle { + objectName: "two" + color: "green" + width: 20 + height: 50 + } + Rectangle { + objectName: "three" + color: "blue" + width: 30 + height: 20 + } + Rectangle { + objectName: "four" + color: "cyan" + width: 50 + height: 50 + } + Rectangle { + objectName: "five" + color: "magenta" + width: 10 + height: 10 + } + } +} diff --git a/tests/auto/quick/qquickpositioners/data/horizontal-padding.qml b/tests/auto/quick/qquickpositioners/data/horizontal-padding.qml new file mode 100644 index 0000000000..d320c4789f --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/horizontal-padding.qml @@ -0,0 +1,30 @@ +import QtQuick 2.6 + +Item { + width: 640 + height: 480 + property bool testRightToLeft: false + Row { + objectName: "row" + layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight + padding: 1; topPadding: 1; leftPadding: 1; rightPadding: 1; bottomPadding: 1 + Rectangle { + objectName: "one" + color: "red" + width: 50 + height: 50 + } + Rectangle { + objectName: "two" + color: "red" + width: 20 + height: 10 + } + Rectangle { + objectName: "three" + color: "red" + width: 40 + height: 20 + } + } +} diff --git a/tests/auto/quick/qquickpositioners/data/repeatertest-padding.qml b/tests/auto/quick/qquickpositioners/data/repeatertest-padding.qml new file mode 100644 index 0000000000..577d4ef0b7 --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/repeatertest-padding.qml @@ -0,0 +1,53 @@ +import QtQuick 2.6 + +Item { + width: 640 + height: 480 + Row { + padding: 1; topPadding: 2; leftPadding: 3; rightPadding: 4; bottomPadding: 5 + Repeater{ model: 3; + delegate: Component { + Rectangle { + color: "red" + width: 50 + height: 50 + z: { + if (index == 0) + return 2; + else if (index == 1) + return 1; + else + return 3; + } + objectName: { + if (index == 0) + return "one"; + else if (index == 1) + return "two"; + else + return "three"; + } + } + } + } + } + + //This crashed once (QTBUG-16959) because the repeater ended up on the end of the list + //If this grid just instantiates without crashing, then it has not regressed. + Grid { + id: grid + rows: 2 + flow: Grid.TopToBottom + + Repeater { + model: 13 + Rectangle { + color: "goldenrod" + width: 100 + height: 100 + radius: 10 + border.width: 1 + } + } + } +} diff --git a/tests/auto/quick/qquickpositioners/data/repeatertest.qml b/tests/auto/quick/qquickpositioners/data/repeatertest.qml index d90e1cf160..ae3d961c75 100644 --- a/tests/auto/quick/qquickpositioners/data/repeatertest.qml +++ b/tests/auto/quick/qquickpositioners/data/repeatertest.qml @@ -10,8 +10,22 @@ Item { color: "red" width: 50 height: 50 - z: {if(index == 0){2;}else if(index == 1){1;} else{3;}} - objectName: {if(index == 0){"one";}else if(index == 1){"two";} else{"three";}} + z: { + if (index == 0) + return 2; + else if (index == 1) + return 1; + else + return 3; + } + objectName: { + if (index == 0) + return "one"; + else if (index == 1) + return "two"; + else + return "three"; + } } } } diff --git a/tests/auto/quick/qquickpositioners/data/transitions-padding.qml b/tests/auto/quick/qquickpositioners/data/transitions-padding.qml new file mode 100644 index 0000000000..e3175c480c --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/transitions-padding.qml @@ -0,0 +1,239 @@ +import QtQuick 2.6 + +Rectangle { + id: root + width: 500 + height: 500 + + property int duration: 50 + + property real incrementalSize: 5 + + property int populateTransitionsDone + property int addTransitionsDone + property int displaceTransitionsDone + + property var targetTrans_items: new Object() + property var targetTrans_targetIndexes: new Array() + property var targetTrans_targetItems: new Array() + + property var displacedTrans_items: new Object() + property var displacedTrans_targetIndexes: new Array() + property var displacedTrans_targetItems: new Array() + + // for QQmlListProperty types + function copyList(propList) { + var temp = new Array() + for (var i=0; i<propList.length; i++) + temp.push(propList[i]) + return temp + } + + function checkPos(x, y, name) { + if (Qt.point(x, y) == targetItems_transitionFrom) + model_targetItems_transitionFrom.addItem(name, "") + if (Qt.point(x, y) == displacedItems_transitionVia) + model_displacedItems_transitionVia.addItem(name, "") + } + + Component.onCompleted: { + if (dynamicallyPopulate) { + for (var i=0; i<30; i++) + testModel.addItem("item " + i, "") + } + } + + Transition { + id: populateTransition + enabled: usePopulateTransition + + SequentialAnimation { + ScriptAction { + script: { + root.targetTrans_items[populateTransition.ViewTransition.item.nameData] = populateTransition.ViewTransition.index + root.targetTrans_targetIndexes.push(populateTransition.ViewTransition.targetIndexes) + root.targetTrans_targetItems.push(root.copyList(populateTransition.ViewTransition.targetItems)) + } + } + ParallelAnimation { + NumberAnimation { properties: "x"; from: targetItems_transitionFrom.x; duration: root.duration } + NumberAnimation { properties: "y"; from: targetItems_transitionFrom.y; duration: root.duration } + } + + ScriptAction { script: root.populateTransitionsDone += 1 } + } + } + + Transition { + id: addTransition + enabled: enableAddTransition + + SequentialAnimation { + ScriptAction { + script: { + root.targetTrans_items[addTransition.ViewTransition.item.nameData] = addTransition.ViewTransition.index + root.targetTrans_targetIndexes.push(addTransition.ViewTransition.targetIndexes) + root.targetTrans_targetItems.push(root.copyList(addTransition.ViewTransition.targetItems)) + } + } + ParallelAnimation { + NumberAnimation { properties: "x"; from: targetItems_transitionFrom.x; duration: root.duration } + NumberAnimation { properties: "y"; from: targetItems_transitionFrom.y; duration: root.duration } + } + + ScriptAction { script: root.addTransitionsDone += 1 } + } + } + + Transition { + id: displaced + + SequentialAnimation { + ScriptAction { + script: { + root.displacedTrans_items[displaced.ViewTransition.item.nameData] = displaced.ViewTransition.index + root.displacedTrans_targetIndexes.push(displaced.ViewTransition.targetIndexes) + root.displacedTrans_targetItems.push(root.copyList(displaced.ViewTransition.targetItems)) + } + } + ParallelAnimation { + NumberAnimation { properties: "x"; duration: root.duration; to: displacedItems_transitionVia.x } + NumberAnimation { properties: "y"; duration: root.duration; to: displacedItems_transitionVia.y } + } + NumberAnimation { properties: "x,y"; duration: root.duration } + + ScriptAction { script: root.displaceTransitionsDone += 1 } + } + + } + + Row { + objectName: "row" + + property int count: children.length - 1 // omit Repeater + + x: 50; y: 50 + width: 400; height: 400 + padding: 1; topPadding: 2; leftPadding: 3; rightPadding: 4; bottomPadding: 5 + Repeater { + objectName: "repeater" + model: testedPositioner == "row" ? testModel : undefined + Rectangle { + property string nameData: name + objectName: "wrapper" + width: 30 + index*root.incrementalSize + height: 30 + index*root.incrementalSize + border.width: 1 + Column { + Text { text: index } + Text { objectName: "name"; text: name } + Text { text: parent.parent.y } + } + onXChanged: root.checkPos(x, y, name) + onYChanged: root.checkPos(x, y, name) + } + } + + populate: populateTransition + add: addTransition + move: displaced + } + + Column { + objectName: "column" + + property int count: children.length - 1 // omit Repeater + + x: 50; y: 50 + width: 400; height: 400 + padding: 1; topPadding: 2; leftPadding: 3; rightPadding: 4; bottomPadding: 5 + Repeater { + objectName: "repeater" + model: testedPositioner == "column" ? testModel : undefined + Rectangle { + property string nameData: name + objectName: "wrapper" + width: 30 + index*root.incrementalSize + height: 30 + index*root.incrementalSize + border.width: 1 + Column { + Text { text: index } + Text { objectName: "name"; text: name } + Text { text: parent.parent.y } + } + onXChanged: root.checkPos(x, y, name) + onYChanged: root.checkPos(x, y, name) + } + } + + populate: populateTransition + add: addTransition + move: displaced + } + + Grid { + objectName: "grid" + + property int count: children.length - 1 // omit Repeater + + x: 50; y: 50 + width: 400; height: 400 + padding: 1; topPadding: 2; leftPadding: 3; rightPadding: 4; bottomPadding: 5 + Repeater { + objectName: "repeater" + model: testedPositioner == "grid" ? testModel : undefined + Rectangle { + property string nameData: name + objectName: "wrapper" + width: 30 + index*root.incrementalSize + height: 30 + index*root.incrementalSize + border.width: 1 + Column { + Text { text: index } + Text { objectName: "name"; text: name } + Text { text: parent.parent.y } + } + + onXChanged: root.checkPos(x, y, name) + onYChanged: root.checkPos(x, y, name) + } + } + + populate: populateTransition + add: addTransition + move: displaced + } + + Flow { + objectName: "flow" + + property int count: children.length - 1 // omit Repeater + + x: 50; y: 50 + width: 400; height: 400 + padding: 1; topPadding: 2; leftPadding: 3; rightPadding: 4; bottomPadding: 5 + Repeater { + objectName: "repeater" + model: testedPositioner == "flow" ? testModel : undefined + Rectangle { + property string nameData: name + objectName: "wrapper" + width: 30 + index*root.incrementalSize + height: 30 + index*root.incrementalSize + border.width: 1 + Column { + Text { text: index } + Text { objectName: "name"; text: name } + Text { text: parent.parent.x + " " + parent.parent.y } + } + onXChanged: root.checkPos(x, y, name) + onYChanged: root.checkPos(x, y, name) + } + } + + populate: populateTransition + add: addTransition + move: displaced + } +} + diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index 3c44041ca5..c68f58383b 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -53,33 +53,50 @@ public: private slots: void test_horizontal(); + void test_horizontal_padding(); void test_horizontal_rtl(); void test_horizontal_spacing(); void test_horizontal_spacing_rightToLeft(); void test_horizontal_animated(); + void test_horizontal_animated_padding(); void test_horizontal_animated_rightToLeft(); + void test_horizontal_animated_rightToLeft_padding(); void test_horizontal_animated_disabled(); + void test_horizontal_animated_disabled_padding(); void test_vertical(); + void test_vertical_padding(); void test_vertical_spacing(); void test_vertical_animated(); + void test_vertical_animated_padding(); void test_grid(); + void test_grid_padding(); void test_grid_topToBottom(); void test_grid_rightToLeft(); void test_grid_spacing(); void test_grid_row_column_spacing(); void test_grid_animated(); + void test_grid_animated_padding(); void test_grid_animated_rightToLeft(); + void test_grid_animated_rightToLeft_padding(); void test_grid_zero_columns(); void test_grid_H_alignment(); + void test_grid_H_alignment_padding(); void test_grid_V_alignment(); + void test_grid_V_alignment_padding(); void test_propertychanges(); void test_repeater(); + void test_repeater_padding(); void test_flow(); + void test_flow_padding(); void test_flow_rightToLeft(); void test_flow_topToBottom(); + void test_flow_topToBottom_padding(); void test_flow_resize(); + void test_flow_resize_padding(); void test_flow_resize_rightToLeft(); + void test_flow_resize_rightToLeft_padding(); void test_flow_implicit_resize(); + void test_flow_implicit_resize_padding(); void test_conflictinganchors(); void test_mirroring(); void test_allInvisible(); @@ -198,18 +215,25 @@ void tst_qquickpositioners::addTransitions_grid_data() // (adding items further down the grid can cause displace transitions at // previous indexes, since grid is auto-resized to tightly fit all of its items) + QTest::addColumn<QString>("qmlFile"); QTest::addColumn<int>("initialItemCount"); QTest::addColumn<int>("insertionIndex"); QTest::addColumn<int>("insertionCount"); QTest::addColumn<ListRange>("expectedDisplacedIndexes"); - QTest::newRow("add one @ start") << 10 << 0 << 1 << ListRange(0, 9); - QTest::newRow("add one @ middle") << 10 << 5 << 1 << ListRange(3, 3) + ListRange(5, 9); - QTest::newRow("add one @ end") << 10 << 10 << 1 << ListRange(3, 3) + ListRange(7, 7); + QTest::newRow("add one @ start") << "transitions.qml" << 10 << 0 << 1 << ListRange(0, 9); + QTest::newRow("add one @ middle") << "transitions.qml" << 10 << 5 << 1 << ListRange(3, 3) + ListRange(5, 9); + QTest::newRow("add one @ end") << "transitions.qml" << 10 << 10 << 1 << ListRange(3, 3) + ListRange(7, 7); + QTest::newRow("padding, add one @ start") << "transitions-padding.qml" << 10 << 0 << 1 << ListRange(0, 9); + QTest::newRow("padding, add one @ middle") << "transitions-padding.qml" << 10 << 5 << 1 << ListRange(3, 3) + ListRange(5, 9); + QTest::newRow("padding, add one @ end") << "transitions-padding.qml" << 10 << 10 << 1 << ListRange(3, 3) + ListRange(7, 7); - QTest::newRow("add multiple @ start") << 10 << 0 << 3 << ListRange(0, 9); - QTest::newRow("add multiple @ middle") << 10 << 5 << 3 << ListRange(1, 3) + ListRange(5, 9); - QTest::newRow("add multiple @ end") << 10 << 10 << 3 << ListRange(1, 3) + ListRange(5, 7) + ListRange(9, 9); + QTest::newRow("add multiple @ start") << "transitions.qml" << 10 << 0 << 3 << ListRange(0, 9); + QTest::newRow("add multiple @ middle") << "transitions.qml" << 10 << 5 << 3 << ListRange(1, 3) + ListRange(5, 9); + QTest::newRow("add multiple @ end") << "transitions.qml" << 10 << 10 << 3 << ListRange(1, 3) + ListRange(5, 7) + ListRange(9, 9); + QTest::newRow("padding, add multiple @ start") << "transitions-padding.qml" << 10 << 0 << 3 << ListRange(0, 9); + QTest::newRow("padding, add multiple @ middle") << "transitions-padding.qml" << 10 << 5 << 3 << ListRange(1, 3) + ListRange(5, 9); + QTest::newRow("padding, add multiple @ end") << "transitions-padding.qml" << 10 << 10 << 3 << ListRange(1, 3) + ListRange(5, 7) + ListRange(9, 9); } void tst_qquickpositioners::addTransitions_flow() @@ -253,17 +277,24 @@ void tst_qquickpositioners::moveTransitions_grid_data() // (removing items further down the grid can cause displace transitions at // previous indexes, since grid is auto-resized to tightly fit all of its items) + QTest::addColumn<QString>("qmlFile"); QTest::addColumn<int>("initialItemCount"); QTest::addColumn<ListChange>("change"); QTest::addColumn<ListRange>("expectedDisplacedIndexes"); - QTest::newRow("remove one @ start") << 10 << ListChange::remove(0, 1) << ListRange(1, 9); - QTest::newRow("remove one @ middle") << 10 << ListChange::remove(4, 1) << ListRange(2, 3) + ListRange(5, 9); - QTest::newRow("remove one @ end") << 10 << ListChange::remove(9, 1) << ListRange(2, 3) + ListRange(6, 7); + QTest::newRow("remove one @ start") << "transitions.qml" << 10 << ListChange::remove(0, 1) << ListRange(1, 9); + QTest::newRow("remove one @ middle") << "transitions.qml" << 10 << ListChange::remove(4, 1) << ListRange(2, 3) + ListRange(5, 9); + QTest::newRow("remove one @ end") << "transitions.qml" << 10 << ListChange::remove(9, 1) << ListRange(2, 3) + ListRange(6, 7); + QTest::newRow("padding, remove one @ start") << "transitions-padding.qml" << 10 << ListChange::remove(0, 1) << ListRange(1, 9); + QTest::newRow("padding, remove one @ middle") << "transitions-padding.qml" << 10 << ListChange::remove(4, 1) << ListRange(2, 3) + ListRange(5, 9); + QTest::newRow("padding, remove one @ end") << "transitions-padding.qml" << 10 << ListChange::remove(9, 1) << ListRange(2, 3) + ListRange(6, 7); - QTest::newRow("remove multiple @ start") << 10 << ListChange::remove(0, 3) << ListRange(3, 9); - QTest::newRow("remove multiple @ middle") << 10 << ListChange::remove(4, 3) << ListRange(1, 3) + ListRange(7, 9); - QTest::newRow("remove multiple @ end") << 10 << ListChange::remove(7, 3) << ListRange(1, 3) + ListRange(5, 6); + QTest::newRow("remove multiple @ start") << "transitions.qml" << 10 << ListChange::remove(0, 3) << ListRange(3, 9); + QTest::newRow("remove multiple @ middle") << "transitions.qml" << 10 << ListChange::remove(4, 3) << ListRange(1, 3) + ListRange(7, 9); + QTest::newRow("remove multiple @ end") << "transitions.qml" << 10 << ListChange::remove(7, 3) << ListRange(1, 3) + ListRange(5, 6); + QTest::newRow("padding, remove multiple @ start") << "transitions-padding.qml" << 10 << ListChange::remove(0, 3) << ListRange(3, 9); + QTest::newRow("padding, remove multiple @ middle") << "transitions-padding.qml" << 10 << ListChange::remove(4, 3) << ListRange(1, 3) + ListRange(7, 9); + QTest::newRow("padding, remove multiple @ end") << "transitions-padding.qml" << 10 << ListChange::remove(7, 3) << ListRange(1, 3) + ListRange(5, 6); } void tst_qquickpositioners::moveTransitions_flow() @@ -305,6 +336,185 @@ void tst_qquickpositioners::test_horizontal() QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); QCOMPARE(row->width(), 110.0); QCOMPARE(row->height(), 50.0); + + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 117.0); + QCOMPARE(row->height(), 57.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); +} + +void tst_qquickpositioners::test_horizontal_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("horizontal.qml"))); + + window->rootObject()->setProperty("testRightToLeft", false); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); + + QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); + QCOMPARE(row->width(), 110.0); + QCOMPARE(row->height(), 50.0); + + QQuickRow *obj = qobject_cast<QQuickRow*>(row); + QVERIFY(obj != 0); + + QCOMPARE(row->property("padding").toDouble(), 0.0); + QCOMPARE(row->property("topPadding").toDouble(), 0.0); + QCOMPARE(row->property("leftPadding").toDouble(), 0.0); + QCOMPARE(row->property("rightPadding").toDouble(), 0.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 0.0); + + obj->setPadding(1.0); + + QCOMPARE(row->property("padding").toDouble(), 1.0); + QCOMPARE(row->property("topPadding").toDouble(), 1.0); + QCOMPARE(row->property("leftPadding").toDouble(), 1.0); + QCOMPARE(row->property("rightPadding").toDouble(), 1.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(row->width(), 112.0); + QCOMPARE(row->height(), 52.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 1.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 1.0); + QCOMPARE(three->x(), 71.0); + QCOMPARE(three->y(), 1.0); + + obj->setTopPadding(2.0); + + QCOMPARE(row->property("padding").toDouble(), 1.0); + QCOMPARE(row->property("topPadding").toDouble(), 2.0); + QCOMPARE(row->property("leftPadding").toDouble(), 1.0); + QCOMPARE(row->property("rightPadding").toDouble(), 1.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(row->height(), 53.0); + QCOMPARE(row->width(), 112.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 71.0); + QCOMPARE(three->y(), 2.0); + + obj->setLeftPadding(3.0); + + QCOMPARE(row->property("padding").toDouble(), 1.0); + QCOMPARE(row->property("topPadding").toDouble(), 2.0); + QCOMPARE(row->property("leftPadding").toDouble(), 3.0); + QCOMPARE(row->property("rightPadding").toDouble(), 1.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(row->width(), 114.0); + QCOMPARE(row->height(), 53.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + + obj->setRightPadding(4.0); + + QCOMPARE(row->property("padding").toDouble(), 1.0); + QCOMPARE(row->property("topPadding").toDouble(), 2.0); + QCOMPARE(row->property("leftPadding").toDouble(), 3.0); + QCOMPARE(row->property("rightPadding").toDouble(), 4.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(row->width(), 117.0); + QCOMPARE(row->height(), 53.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + + obj->setBottomPadding(5.0); + + QCOMPARE(row->property("padding").toDouble(), 1.0); + QCOMPARE(row->property("topPadding").toDouble(), 2.0); + QCOMPARE(row->property("leftPadding").toDouble(), 3.0); + QCOMPARE(row->property("rightPadding").toDouble(), 4.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 5.0); + + QTRY_COMPARE(row->height(), 57.0); + QCOMPARE(row->width(), 117.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + + obj->resetBottomPadding(); + QCOMPARE(row->property("bottomPadding").toDouble(), 1.0); + QTRY_COMPARE(row->height(), 53.0); + QCOMPARE(row->width(), 117.0); + + obj->resetRightPadding(); + QCOMPARE(row->property("rightPadding").toDouble(), 1.0); + QTRY_COMPARE(row->width(), 114.0); + QCOMPARE(row->height(), 53.0); + + obj->resetLeftPadding(); + QCOMPARE(row->property("leftPadding").toDouble(), 1.0); + QTRY_COMPARE(row->width(), 112.0); + QCOMPARE(row->height(), 53.0); + + obj->resetTopPadding(); + QCOMPARE(row->property("topPadding").toDouble(), 1.0); + QTRY_COMPARE(row->height(), 52.0); + QCOMPARE(row->width(), 112.0); + + obj->resetPadding(); + QCOMPARE(row->property("padding").toDouble(), 0.0); + QCOMPARE(row->property("topPadding").toDouble(), 0.0); + QCOMPARE(row->property("leftPadding").toDouble(), 0.0); + QCOMPARE(row->property("rightPadding").toDouble(), 0.0); + QCOMPARE(row->property("bottomPadding").toDouble(), 0.0); + QTRY_COMPARE(row->height(), 50.0); + QCOMPARE(row->width(), 110.0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); } void tst_qquickpositioners::test_horizontal_rtl() @@ -333,6 +543,36 @@ void tst_qquickpositioners::test_horizontal_rtl() QCOMPARE(row->width(), 110.0); QCOMPARE(row->height(), 50.0); + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 117.0); + QCOMPARE(row->height(), 57.0); + + QCOMPARE(one->x(), 63.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 43.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 2.0); + + row->setProperty("topPadding", 0); + row->setProperty("leftPadding", 0); + row->setProperty("rightPadding", 0); + row->setProperty("bottomPadding", 0); + row->setProperty("padding", 0); + + QTRY_COMPARE(one->x(), 60.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 40.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 0.0); + // Change the width of the row and check that items stay to the right row->setWidth(200); QTRY_COMPARE(one->x(), 150.0); @@ -342,6 +582,18 @@ void tst_qquickpositioners::test_horizontal_rtl() QCOMPARE(three->x(), 90.0); QCOMPARE(three->y(), 0.0); + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(one->x(), 146.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 126.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 86.0); + QCOMPARE(three->y(), 2.0); } void tst_qquickpositioners::test_horizontal_spacing() @@ -370,6 +622,22 @@ void tst_qquickpositioners::test_horizontal_spacing() QCOMPARE(row->width(), 130.0); QCOMPARE(row->height(), 50.0); + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 137.0); + QCOMPARE(row->height(), 57.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 63.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 93.0); + QCOMPARE(three->y(), 2.0); } void tst_qquickpositioners::test_horizontal_spacing_rightToLeft() @@ -391,13 +659,29 @@ void tst_qquickpositioners::test_horizontal_spacing_rightToLeft() QCOMPARE(one->y(), 0.0); QCOMPARE(two->x(), 50.0); QCOMPARE(two->y(), 0.0); - QCOMPARE(three->x(), 00.0); + QCOMPARE(three->x(), 0.0); QCOMPARE(three->y(), 0.0); QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); QCOMPARE(row->width(), 130.0); QCOMPARE(row->height(), 50.0); + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 137.0); + QCOMPARE(row->height(), 57.0); + + QCOMPARE(one->x(), 83.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 2.0); } void tst_qquickpositioners::test_horizontal_animated() @@ -453,6 +737,70 @@ void tst_qquickpositioners::test_horizontal_animated() } +void tst_qquickpositioners::test_horizontal_animated_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated.qml"), false)); + + window->rootObject()->setProperty("testRightToLeft", false); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + + //Note that they animate in + QCOMPARE(one->x(), -100.0); + QCOMPARE(two->x(), -100.0); + QCOMPARE(three->x(), -100.0); + + QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn + + QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); + QVERIFY(row); + QCOMPARE(row->width(), 100.0); + QCOMPARE(row->height(), 50.0); + + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 107.0); + QCOMPARE(row->height(), 57.0); + + //QTRY_COMPARE used instead of waiting for the expected time of animation completion + //Note that this means the duration of the animation is NOT tested + + QTRY_COMPARE(one->x(), 3.0); + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(two->isVisible(), false); + QTRY_COMPARE(two->x(), -100.0);//Not 'in' yet + QTRY_COMPARE(two->y(), 0.0); + QTRY_COMPARE(three->x(), 53.0); + QTRY_COMPARE(three->y(), 2.0); + + //Add 'two' + two->setVisible(true); + QTRY_COMPARE(two->isVisible(), true); + QTRY_COMPARE(row->width(), 157.0); + QTRY_COMPARE(row->height(), 57.0); + + QTest::qWait(0);//Let the animation start + QVERIFY(two->x() >= -100.0 && two->x() < 53.0); + QVERIFY(three->x() >= 53.0 && three->x() < 103.0); + + QTRY_COMPARE(two->y(), 2.0); + QTRY_COMPARE(two->x(), 53.0); + QTRY_COMPARE(three->x(), 103.0); + +} + void tst_qquickpositioners::test_horizontal_animated_rightToLeft() { QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated.qml"), false)); @@ -508,6 +856,72 @@ void tst_qquickpositioners::test_horizontal_animated_rightToLeft() } +void tst_qquickpositioners::test_horizontal_animated_rightToLeft_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated.qml"), false)); + + window->rootObject()->setProperty("testRightToLeft", true); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + + //Note that they animate in + QCOMPARE(one->x(), -100.0); + QCOMPARE(two->x(), -100.0); + QCOMPARE(three->x(), -100.0); + + QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn + + QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); + QVERIFY(row); + QCOMPARE(row->width(), 100.0); + QCOMPARE(row->height(), 50.0); + + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 107.0); + QCOMPARE(row->height(), 57.0); + + //QTRY_COMPARE used instead of waiting for the expected time of animation completion + //Note that this means the duration of the animation is NOT tested + + QTRY_COMPARE(one->x(), 53.0); + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(two->isVisible(), false); + QTRY_COMPARE(two->x(), -100.0);//Not 'in' yet + QTRY_COMPARE(two->y(), 0.0); + QTRY_COMPARE(three->x(), 3.0); + QTRY_COMPARE(three->y(), 2.0); + + //Add 'two' + two->setVisible(true); + QTRY_COMPARE(two->isVisible(), true); + + // New size should propagate after visible change + QTRY_COMPARE(row->width(), 157.0); + QTRY_COMPARE(row->height(), 57.0); + + QTest::qWait(0);//Let the animation start + QVERIFY(one->x() >= 53.0 && one->x() < 100); + QVERIFY(two->x() >= -100.0 && two->x() < 53.0); + + QTRY_COMPARE(one->x(), 103.0); + QTRY_COMPARE(two->y(), 2.0); + QTRY_COMPARE(two->x(), 53.0); + +} + void tst_qquickpositioners::test_horizontal_animated_disabled() { QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated-disabled.qml"))); @@ -526,6 +940,54 @@ void tst_qquickpositioners::test_horizontal_animated_disabled() qApp->processEvents(); + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->width(), 107.0); + QCOMPARE(row->height(), 57.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->isVisible(), false); + QCOMPARE(two->x(), -100.0);//Not 'in' yet + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 53.0); + QCOMPARE(three->y(), 2.0); + + //Add 'two' + two->setVisible(true); + QCOMPARE(two->isVisible(), true); + QTRY_COMPARE(row->width(), 157.0); + QTRY_COMPARE(row->height(), 57.0); + + QTRY_COMPARE(two->y(), 2.0); + QTRY_COMPARE(two->x(), 53.0); + QTRY_COMPARE(three->x(), 103.0); + +} + +void tst_qquickpositioners::test_horizontal_animated_disabled_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated-disabled.qml"))); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + + QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); + QVERIFY(row); + + qApp->processEvents(); + QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); QCOMPARE(two->isVisible(), false); @@ -547,6 +1009,7 @@ void tst_qquickpositioners::test_horizontal_animated_disabled() void tst_qquickpositioners::populateTransitions(const QString &positionerObjectName) { + QFETCH(QString, qmlFile); QFETCH(bool, dynamicallyPopulate); QFETCH(bool, usePopulateTransition); @@ -574,7 +1037,7 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); ctxt->setContextProperty("testedPositioner", positionerObjectName); - window->setSource(testFileUrl("transitions.qml")); + window->setSource(testFileUrl(qmlFile)); QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName); QVERIFY(positioner); @@ -619,18 +1082,24 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN void tst_qquickpositioners::populateTransitions_data() { + QTest::addColumn<QString>("qmlFile"); QTest::addColumn<bool>("dynamicallyPopulate"); QTest::addColumn<bool>("usePopulateTransition"); - QTest::newRow("statically populate") << false << true; - QTest::newRow("statically populate, no populate transition") << false << false; + QTest::newRow("statically populate") << "transitions.qml" << false << true; + QTest::newRow("statically populate, no populate transition") << "transitions.qml" << false << false; + QTest::newRow("padding, statically populate") << "transitions-padding.qml" << false << true; + QTest::newRow("padding, statically populate, no populate transition") << "transitions-padding.qml" << false << false; - QTest::newRow("dynamically populate") << true << true; - QTest::newRow("dynamically populate, no populate transition") << true << false; + QTest::newRow("dynamically populate") << "transitions.qml" << true << true; + QTest::newRow("dynamically populate, no populate transition") << "transitions.qml" << true << false; + QTest::newRow("padding, dynamically populate") << "transitions-padding.qml" << true << true; + QTest::newRow("padding, dynamically populate, no populate transition") << "transitions-padding.qml" << true << false; } void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) { + QFETCH(QString, qmlFile); QFETCH(int, initialItemCount); QFETCH(int, insertionIndex); QFETCH(int, insertionCount); @@ -654,7 +1123,7 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); ctxt->setContextProperty("testedPositioner", QString()); - window->setSource(testFileUrl("transitions.qml")); + window->setSource(testFileUrl(qmlFile)); window->show(); QTest::qWaitForWindowExposed(window.data()); qApp->processEvents(); @@ -729,22 +1198,30 @@ void tst_qquickpositioners::addTransitions_data() { // If this data changes, update addTransitions_grid_data() also + QTest::addColumn<QString>("qmlFile"); QTest::addColumn<int>("initialItemCount"); QTest::addColumn<int>("insertionIndex"); QTest::addColumn<int>("insertionCount"); QTest::addColumn<ListRange>("expectedDisplacedIndexes"); - QTest::newRow("add one @ start") << 10 << 0 << 1 << ListRange(0, 9); - QTest::newRow("add one @ middle") << 10 << 5 << 1 << ListRange(5, 9); - QTest::newRow("add one @ end") << 10 << 10 << 1 << ListRange(); + QTest::newRow("add one @ start") << "transitions.qml" << 10 << 0 << 1 << ListRange(0, 9); + QTest::newRow("add one @ middle") << "transitions.qml" << 10 << 5 << 1 << ListRange(5, 9); + QTest::newRow("add one @ end") << "transitions.qml" << 10 << 10 << 1 << ListRange(); + QTest::newRow("padding, add one @ start") << "transitions-padding.qml" << 10 << 0 << 1 << ListRange(0, 9); + QTest::newRow("padding, add one @ middle") << "transitions-padding.qml" << 10 << 5 << 1 << ListRange(5, 9); + QTest::newRow("padding, add one @ end") << "transitions-padding.qml" << 10 << 10 << 1 << ListRange(); - QTest::newRow("add multiple @ start") << 10 << 0 << 3 << ListRange(0, 9); - QTest::newRow("add multiple @ middle") << 10 << 5 << 3 << ListRange(5, 9); - QTest::newRow("add multiple @ end") << 10 << 10 << 3 << ListRange(); + QTest::newRow("add multiple @ start") << "transitions.qml" << 10 << 0 << 3 << ListRange(0, 9); + QTest::newRow("add multiple @ middle") << "transitions.qml" << 10 << 5 << 3 << ListRange(5, 9); + QTest::newRow("add multiple @ end") << "transitions.qml" << 10 << 10 << 3 << ListRange(); + QTest::newRow("padding, add multiple @ start") << "transitions-padding.qml" << 10 << 0 << 3 << ListRange(0, 9); + QTest::newRow("padding, add multiple @ middle") << "transitions-padding.qml" << 10 << 5 << 3 << ListRange(5, 9); + QTest::newRow("padding, add multiple @ end") << "transitions-padding.qml" << 10 << 10 << 3 << ListRange(); } void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) { + QFETCH(QString, qmlFile); QFETCH(int, initialItemCount); QFETCH(ListChange, change); QFETCH(ListRange, expectedDisplacedIndexes); @@ -769,7 +1246,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); ctxt->setContextProperty("testedPositioner", QString()); - window->setSource(testFileUrl("transitions.qml")); + window->setSource(testFileUrl(qmlFile)); window->show(); QTest::qWaitForWindowExposed(window.data()); qApp->processEvents(); @@ -840,27 +1317,36 @@ void tst_qquickpositioners::moveTransitions_data() { // If this data changes, update moveTransitions_grid_data() also + QTest::addColumn<QString>("qmlFile"); QTest::addColumn<int>("initialItemCount"); QTest::addColumn<ListChange>("change"); QTest::addColumn<ListRange>("expectedDisplacedIndexes"); - QTest::newRow("remove one @ start") << 10 << ListChange::remove(0, 1) << ListRange(1, 9); - QTest::newRow("remove one @ middle") << 10 << ListChange::remove(4, 1) << ListRange(5, 9); - QTest::newRow("remove one @ end") << 10 << ListChange::remove(9, 1) << ListRange(); + QTest::newRow("remove one @ start") << "transitions.qml" << 10 << ListChange::remove(0, 1) << ListRange(1, 9); + QTest::newRow("remove one @ middle") << "transitions.qml" << 10 << ListChange::remove(4, 1) << ListRange(5, 9); + QTest::newRow("remove one @ end") << "transitions.qml" << 10 << ListChange::remove(9, 1) << ListRange(); + QTest::newRow("padding, remove one @ start") << "transitions-padding.qml" << 10 << ListChange::remove(0, 1) << ListRange(1, 9); + QTest::newRow("padding, remove one @ middle") << "transitions-padding.qml" << 10 << ListChange::remove(4, 1) << ListRange(5, 9); + QTest::newRow("padding, remove one @ end") << "transitions-padding.qml" << 10 << ListChange::remove(9, 1) << ListRange(); - QTest::newRow("remove multiple @ start") << 10 << ListChange::remove(0, 3) << ListRange(3, 9); - QTest::newRow("remove multiple @ middle") << 10 << ListChange::remove(4, 3) << ListRange(7, 9); - QTest::newRow("remove multiple @ end") << 10 << ListChange::remove(7, 3) << ListRange(); + QTest::newRow("remove multiple @ start") << "transitions.qml" << 10 << ListChange::remove(0, 3) << ListRange(3, 9); + QTest::newRow("remove multiple @ middle") << "transitions.qml" << 10 << ListChange::remove(4, 3) << ListRange(7, 9); + QTest::newRow("remove multiple @ end") << "transitions.qml" << 10 << ListChange::remove(7, 3) << ListRange(); + QTest::newRow("padding, remove multiple @ start") << "transitions-padding.qml" << 10 << ListChange::remove(0, 3) << ListRange(3, 9); + QTest::newRow("padding, remove multiple @ middle") << "transitions-padding.qml" << 10 << ListChange::remove(4, 3) << ListRange(7, 9); + QTest::newRow("padding, remove multiple @ end") << "transitions-padding.qml" << 10 << ListChange::remove(7, 3) << ListRange(); } - void tst_qquickpositioners::checkItemPositions(QQuickItem *positioner, QaimModel *model, qreal incrementalSize) { QVERIFY(model->count() > 0); + + QQuickBasePositioner *p = qobject_cast<QQuickBasePositioner*>(positioner); + qreal padding = 0; qreal currentSize = 30; - qreal rowX = 0; - qreal rowY = 0; + qreal rowX = p->leftPadding(); + qreal rowY = p->topPadding(); for (int i=0; i<model->count(); ++i) { QQuickItem *item = findItem<QQuickItem>(positioner, "wrapper", i); @@ -870,11 +1356,11 @@ void tst_qquickpositioners::checkItemPositions(QQuickItem *positioner, QaimModel QCOMPARE(item->height(), currentSize); if (qobject_cast<QQuickRow*>(positioner)) { - QCOMPARE(item->x(), (i * 30.0) + padding); - QCOMPARE(item->y(), 0.0); + QCOMPARE(item->x(), (i * 30.0) + padding + p->leftPadding()); + QCOMPARE(item->y(), p->topPadding()); } else if (qobject_cast<QQuickColumn*>(positioner)) { - QCOMPARE(item->x(), 0.0); - QCOMPARE(item->y(), (i * 30.0) + padding); + QCOMPARE(item->x(), p->leftPadding()); + QCOMPARE(item->y(), (i * 30.0) + padding + p->topPadding()); } else if (qobject_cast<QQuickGrid*>(positioner)) { int columns = 4; int rows = qCeil(model->count() / qreal(columns)); @@ -886,20 +1372,20 @@ void tst_qquickpositioners::checkItemPositions(QQuickItem *positioner, QaimModel QVERIFY(finalAlignedRowItem); QCOMPARE(item->x(), finalAlignedRowItem->x()); } else { - QCOMPARE(item->x(), 0.0); + QCOMPARE(item->x(), p->leftPadding()); } if (i / columns > 0) { QQuickItem *prevRowLastItem = findItem<QQuickItem>(positioner, "wrapper", (i/columns * columns) - 1); QVERIFY(prevRowLastItem); QCOMPARE(item->y(), prevRowLastItem->y() + prevRowLastItem->height()); } else { - QCOMPARE(item->y(), 0.0); + QCOMPARE(item->y(), p->topPadding()); } } else if (qobject_cast<QQuickFlow*>(positioner)) { if (rowX + item->width() > positioner->width()) { QQuickItem *prevItem = findItem<QQuickItem>(positioner, "wrapper", i-1); QVERIFY(prevItem); - rowX = 0; + rowX = p->leftPadding(); rowY = prevItem->y() + prevItem->height(); } QCOMPARE(item->x(), rowX); @@ -942,6 +1428,183 @@ void tst_qquickpositioners::test_vertical() QCOMPARE(column->height(), 80.0); QCOMPARE(column->width(), 50.0); + // test padding + column->setProperty("padding", 1); + column->setProperty("topPadding", 2); + column->setProperty("leftPadding", 3); + column->setProperty("rightPadding", 4); + column->setProperty("bottomPadding", 5); + + QTRY_COMPARE(column->height(), 87.0); + QCOMPARE(column->width(), 57.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 3.0); + QCOMPARE(two->y(), 52.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 62.0); +} + +void tst_qquickpositioners::test_vertical_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("vertical.qml"))); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 0.0); + QCOMPARE(two->y(), 50.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 60.0); + + QQuickItem *column = window->rootObject()->findChild<QQuickItem*>("column"); + QVERIFY(column); + QCOMPARE(column->height(), 80.0); + QCOMPARE(column->width(), 50.0); + + QQuickColumn *obj = qobject_cast<QQuickColumn*>(column); + QVERIFY(obj != 0); + + QCOMPARE(column->property("padding").toDouble(), 0.0); + QCOMPARE(column->property("topPadding").toDouble(), 0.0); + QCOMPARE(column->property("leftPadding").toDouble(), 0.0); + QCOMPARE(column->property("rightPadding").toDouble(), 0.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 0.0); + + obj->setPadding(1.0); + + QCOMPARE(column->property("padding").toDouble(), 1.0); + QCOMPARE(column->property("topPadding").toDouble(), 1.0); + QCOMPARE(column->property("leftPadding").toDouble(), 1.0); + QCOMPARE(column->property("rightPadding").toDouble(), 1.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(column->height(), 82.0); + QCOMPARE(column->width(), 52.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 1.0); + QCOMPARE(two->x(), 1.0); + QCOMPARE(two->y(), 51.0); + QCOMPARE(three->x(), 1.0); + QCOMPARE(three->y(), 61.0); + + obj->setTopPadding(2.0); + + QCOMPARE(column->property("padding").toDouble(), 1.0); + QCOMPARE(column->property("topPadding").toDouble(), 2.0); + QCOMPARE(column->property("leftPadding").toDouble(), 1.0); + QCOMPARE(column->property("rightPadding").toDouble(), 1.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(column->height(), 83.0); + QCOMPARE(column->width(), 52.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 1.0); + QCOMPARE(two->y(), 52.0); + QCOMPARE(three->x(), 1.0); + QCOMPARE(three->y(), 62.0); + + obj->setLeftPadding(3.0); + + QCOMPARE(column->property("padding").toDouble(), 1.0); + QCOMPARE(column->property("topPadding").toDouble(), 2.0); + QCOMPARE(column->property("leftPadding").toDouble(), 3.0); + QCOMPARE(column->property("rightPadding").toDouble(), 1.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(column->width(), 54.0); + QCOMPARE(column->height(), 83.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 3.0); + QCOMPARE(two->y(), 52.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 62.0); + + obj->setRightPadding(4.0); + + QCOMPARE(column->property("padding").toDouble(), 1.0); + QCOMPARE(column->property("topPadding").toDouble(), 2.0); + QCOMPARE(column->property("leftPadding").toDouble(), 3.0); + QCOMPARE(column->property("rightPadding").toDouble(), 4.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(column->width(), 57.0); + QCOMPARE(column->height(), 83.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 3.0); + QCOMPARE(two->y(), 52.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 62.0); + + obj->setBottomPadding(5.0); + + QCOMPARE(column->property("padding").toDouble(), 1.0); + QCOMPARE(column->property("topPadding").toDouble(), 2.0); + QCOMPARE(column->property("leftPadding").toDouble(), 3.0); + QCOMPARE(column->property("rightPadding").toDouble(), 4.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 5.0); + + QTRY_COMPARE(column->height(), 87.0); + QCOMPARE(column->width(), 57.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 3.0); + QCOMPARE(two->y(), 52.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 62.0); + + obj->resetBottomPadding(); + QCOMPARE(column->property("bottomPadding").toDouble(), 1.0); + QTRY_COMPARE(column->height(), 83.0); + QCOMPARE(column->width(), 57.0); + + obj->resetRightPadding(); + QCOMPARE(column->property("rightPadding").toDouble(), 1.0); + QTRY_COMPARE(column->width(), 54.0); + QCOMPARE(column->height(), 83.0); + + obj->resetLeftPadding(); + QCOMPARE(column->property("leftPadding").toDouble(), 1.0); + QTRY_COMPARE(column->width(), 52.0); + QCOMPARE(column->height(), 83.0); + + obj->resetTopPadding(); + QCOMPARE(column->property("topPadding").toDouble(), 1.0); + QTRY_COMPARE(column->height(), 82.0); + QCOMPARE(column->width(), 52.0); + + obj->resetPadding(); + QCOMPARE(column->property("padding").toDouble(), 0.0); + QCOMPARE(column->property("topPadding").toDouble(), 0.0); + QCOMPARE(column->property("leftPadding").toDouble(), 0.0); + QCOMPARE(column->property("rightPadding").toDouble(), 0.0); + QCOMPARE(column->property("bottomPadding").toDouble(), 0.0); + QTRY_COMPARE(column->height(), 80.0); + QCOMPARE(column->width(), 50.0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 0.0); + QCOMPARE(two->y(), 50.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 60.0); } void tst_qquickpositioners::test_vertical_spacing() @@ -968,6 +1631,22 @@ void tst_qquickpositioners::test_vertical_spacing() QCOMPARE(column->height(), 100.0); QCOMPARE(column->width(), 50.0); + // test padding + column->setProperty("padding", 1); + column->setProperty("topPadding", 2); + column->setProperty("leftPadding", 3); + column->setProperty("rightPadding", 4); + column->setProperty("bottomPadding", 5); + + QTRY_COMPARE(column->height(), 107.0); + QCOMPARE(column->width(), 57.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 3.0); + QCOMPARE(two->y(), 62.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 82.0); } void tst_qquickpositioners::test_vertical_animated() @@ -1019,6 +1698,66 @@ void tst_qquickpositioners::test_vertical_animated() } +void tst_qquickpositioners::test_vertical_animated_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("vertical-animated.qml"), false)); + + //Note that they animate in + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QCOMPARE(one->y(), -100.0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QCOMPARE(two->y(), -100.0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QCOMPARE(three->y(), -100.0); + + QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn + + QQuickItem *column = window->rootObject()->findChild<QQuickItem*>("column"); + QVERIFY(column); + QCOMPARE(column->height(), 100.0); + QCOMPARE(column->width(), 50.0); + + // test padding + column->setProperty("padding", 1); + column->setProperty("topPadding", 2); + column->setProperty("leftPadding", 3); + column->setProperty("rightPadding", 4); + column->setProperty("bottomPadding", 5); + + QTRY_COMPARE(column->height(), 107.0); + QCOMPARE(column->width(), 57.0); + + //QTRY_COMPARE used instead of waiting for the expected time of animation completion + //Note that this means the duration of the animation is NOT tested + + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(one->x(), 3.0); + QTRY_COMPARE(two->isVisible(), false); + QTRY_COMPARE(two->y(), -100.0);//Not 'in' yet + QTRY_COMPARE(two->x(), 0.0); + QTRY_COMPARE(three->y(), 52.0); + QTRY_COMPARE(three->x(), 3.0); + + //Add 'two' + two->setVisible(true); + QTRY_COMPARE(two->isVisible(), true); + QTRY_COMPARE(column->height(), 157.0); + QTRY_COMPARE(column->width(), 57.0); + QTest::qWait(0);//Let the animation start + QVERIFY(two->y() >= -100.0 && two->y() < 52.0); + QVERIFY(three->y() >= 52.0 && three->y() < 102.0); + + QTRY_COMPARE(two->x(), 3.0); + QTRY_COMPARE(two->y(), 52.0); + QTRY_COMPARE(three->y(), 102.0); + +} + void tst_qquickpositioners::test_grid() { QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); @@ -1050,6 +1789,214 @@ void tst_qquickpositioners::test_grid() QCOMPARE(grid->width(), 100.0); QCOMPARE(grid->height(), 100.0); + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 52.0); +} + +void tst_qquickpositioners::test_grid_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 50.0); + QCOMPARE(five->x(), 50.0); + QCOMPARE(five->y(), 50.0); + + QQuickGrid *grid = window->rootObject()->findChild<QQuickGrid*>("grid"); + QCOMPARE(grid->flow(), QQuickGrid::LeftToRight); + QCOMPARE(grid->width(), 100.0); + QCOMPARE(grid->height(), 100.0); + + QCOMPARE(grid->property("padding").toDouble(), 0.0); + QCOMPARE(grid->property("topPadding").toDouble(), 0.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 0.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 0.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 0.0); + + grid->setPadding(1.0); + + QCOMPARE(grid->property("padding").toDouble(), 1.0); + QCOMPARE(grid->property("topPadding").toDouble(), 1.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 1.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 1.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(grid->width(), 102.0); + QCOMPARE(grid->height(), 102.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 1.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 1.0); + QCOMPARE(three->x(), 71.0); + QCOMPARE(three->y(), 1.0); + QCOMPARE(four->x(), 1.0); + QCOMPARE(four->y(), 51.0); + QCOMPARE(five->x(), 51.0); + QCOMPARE(five->y(), 51.0); + + grid->setTopPadding(2.0); + + QCOMPARE(grid->property("padding").toDouble(), 1.0); + QCOMPARE(grid->property("topPadding").toDouble(), 2.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 1.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 1.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(grid->height(), 103.0); + QCOMPARE(grid->width(), 102.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 71.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 1.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 51.0); + QCOMPARE(five->y(), 52.0); + + grid->setLeftPadding(3.0); + + QCOMPARE(grid->property("padding").toDouble(), 1.0); + QCOMPARE(grid->property("topPadding").toDouble(), 2.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 3.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 1.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(grid->width(), 104.0); + QCOMPARE(grid->height(), 103.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 52.0); + + grid->setRightPadding(4.0); + + QCOMPARE(grid->property("padding").toDouble(), 1.0); + QCOMPARE(grid->property("topPadding").toDouble(), 2.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 3.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 4.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 103.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 52.0); + + grid->setBottomPadding(5.0); + + QCOMPARE(grid->property("padding").toDouble(), 1.0); + QCOMPARE(grid->property("topPadding").toDouble(), 2.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 3.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 4.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 5.0); + + QTRY_COMPARE(grid->height(), 107.0); + QCOMPARE(grid->width(), 107.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 52.0); + + grid->resetBottomPadding(); + QCOMPARE(grid->property("bottomPadding").toDouble(), 1.0); + QTRY_COMPARE(grid->height(), 103.0); + QCOMPARE(grid->width(), 107.0); + + grid->resetRightPadding(); + QCOMPARE(grid->property("rightPadding").toDouble(), 1.0); + QTRY_COMPARE(grid->width(), 104.0); + QCOMPARE(grid->height(), 103.0); + + grid->resetLeftPadding(); + QCOMPARE(grid->property("leftPadding").toDouble(), 1.0); + QTRY_COMPARE(grid->width(), 102.0); + QCOMPARE(grid->height(), 103.0); + + grid->resetTopPadding(); + QCOMPARE(grid->property("topPadding").toDouble(), 1.0); + QTRY_COMPARE(grid->height(), 102.0); + QCOMPARE(grid->width(), 102.0); + + grid->resetPadding(); + QCOMPARE(grid->property("padding").toDouble(), 0.0); + QCOMPARE(grid->property("topPadding").toDouble(), 0.0); + QCOMPARE(grid->property("leftPadding").toDouble(), 0.0); + QCOMPARE(grid->property("rightPadding").toDouble(), 0.0); + QCOMPARE(grid->property("bottomPadding").toDouble(), 0.0); + QTRY_COMPARE(grid->height(), 100.0); + QCOMPARE(grid->width(), 100.0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 50.0); + QCOMPARE(five->x(), 50.0); + QCOMPARE(five->y(), 50.0); } void tst_qquickpositioners::test_grid_topToBottom() @@ -1083,6 +2030,26 @@ void tst_qquickpositioners::test_grid_topToBottom() QCOMPARE(grid->width(), 100.0); QCOMPARE(grid->height(), 120.0); + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 127.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 3.0); + QCOMPARE(two->y(), 52.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 102.0); + QCOMPARE(four->x(), 53.0); + QCOMPARE(four->y(), 2.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 52.0); } void tst_qquickpositioners::test_grid_rightToLeft() @@ -1118,6 +2085,44 @@ void tst_qquickpositioners::test_grid_rightToLeft() QCOMPARE(grid->width(), 100.0); QCOMPARE(grid->height(), 100.0); + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + + QCOMPARE(one->x(), 53.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 33.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 53.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 43.0); + QCOMPARE(five->y(), 52.0); + + grid->setProperty("topPadding", 0); + grid->setProperty("leftPadding", 0); + grid->setProperty("rightPadding", 0); + grid->setProperty("bottomPadding", 0); + grid->setProperty("padding", 0); + + QTRY_COMPARE(one->x(), 50.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 30.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 0.0); + QCOMPARE(four->x(), 50.0); + QCOMPARE(four->y(), 50.0); + QCOMPARE(five->x(), 40.0); + QCOMPARE(five->y(), 50.0); + // Change the width of the grid and check that items stay to the right grid->setWidth(200); QTRY_COMPARE(one->x(), 150.0); @@ -1131,6 +2136,22 @@ void tst_qquickpositioners::test_grid_rightToLeft() QCOMPARE(five->x(), 140.0); QCOMPARE(five->y(), 50.0); + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(one->x(), 146.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 126.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 96.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 146.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 136.0); + QCOMPARE(five->y(), 52.0); } void tst_qquickpositioners::test_grid_spacing() @@ -1163,6 +2184,26 @@ void tst_qquickpositioners::test_grid_spacing() QCOMPARE(grid->width(), 128.0); QCOMPARE(grid->height(), 104.0); + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 135.0); + QCOMPARE(grid->height(), 111.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 57.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 81.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 56.0); + QCOMPARE(five->x(), 57.0); + QCOMPARE(five->y(), 56.0); } void tst_qquickpositioners::test_grid_row_column_spacing() @@ -1195,6 +2236,26 @@ void tst_qquickpositioners::test_grid_row_column_spacing() QCOMPARE(grid->width(), 142.0); QCOMPARE(grid->height(), 107.0); + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 149.0); + QCOMPARE(grid->height(), 114.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 64.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 95.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 59.0); + QCOMPARE(five->x(), 64.0); + QCOMPARE(five->y(), 59.0); } void tst_qquickpositioners::test_grid_animated() @@ -1281,6 +2342,100 @@ void tst_qquickpositioners::test_grid_animated() } +void tst_qquickpositioners::test_grid_animated_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("grid-animated.qml"), false)); + + window->rootObject()->setProperty("testRightToLeft", false); + + //Note that all animate in + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QCOMPARE(one->x(), -100.0); + QCOMPARE(one->y(), -100.0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QCOMPARE(two->x(), -100.0); + QCOMPARE(two->y(), -100.0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QCOMPARE(three->x(), -100.0); + QCOMPARE(three->y(), -100.0); + + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QCOMPARE(four->x(), -100.0); + QCOMPARE(four->y(), -100.0); + + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + QCOMPARE(five->x(), -100.0); + QCOMPARE(five->y(), -100.0); + + QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn + + QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid"); + QVERIFY(grid); + QCOMPARE(grid->width(), 150.0); + QCOMPARE(grid->height(), 100.0); + + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 157.0); + QCOMPARE(grid->height(), 107.0); + + //QTRY_COMPARE used instead of waiting for the expected time of animation completion + //Note that this means the duration of the animation is NOT tested + + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(one->x(), 3.0); + QTRY_COMPARE(two->isVisible(), false); + QTRY_COMPARE(two->y(), -100.0); + QTRY_COMPARE(two->x(), -100.0); + QTRY_COMPARE(three->y(), 2.0); + QTRY_COMPARE(three->x(), 53.0); + QTRY_COMPARE(four->y(), 2.0); + QTRY_COMPARE(four->x(), 103.0); + QTRY_COMPARE(five->y(), 52.0); + QTRY_COMPARE(five->x(), 3.0); + + //Add 'two' + two->setVisible(true); + QCOMPARE(two->isVisible(), true); + QCOMPARE(grid->width(), 157.0); + QCOMPARE(grid->height(), 107.0); + QTest::qWait(0);//Let the animation start + QCOMPARE(two->x(), -100.0); + QCOMPARE(two->y(), -100.0); + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(three->x(), 53.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 103.0); + QCOMPARE(four->y(), 2.0); + QCOMPARE(five->x(), 3.0); + QCOMPARE(five->y(), 52.0); + //Let the animation complete + QTRY_COMPARE(two->x(), 53.0); + QTRY_COMPARE(two->y(), 2.0); + QTRY_COMPARE(one->x(), 3.0); + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(three->x(), 103.0); + QTRY_COMPARE(three->y(), 2.0); + QTRY_COMPARE(four->x(), 3.0); + QTRY_COMPARE(four->y(), 52.0); + QTRY_COMPARE(five->x(), 53.0); + QTRY_COMPARE(five->y(), 52.0); + +} + void tst_qquickpositioners::test_grid_animated_rightToLeft() { QScopedPointer<QQuickView> window(createView(testFile("grid-animated.qml"), false)); @@ -1365,6 +2520,100 @@ void tst_qquickpositioners::test_grid_animated_rightToLeft() } +void tst_qquickpositioners::test_grid_animated_rightToLeft_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("grid-animated.qml"), false)); + + window->rootObject()->setProperty("testRightToLeft", true); + + //Note that all animate in + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QCOMPARE(one->x(), -100.0); + QCOMPARE(one->y(), -100.0); + + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QCOMPARE(two->x(), -100.0); + QCOMPARE(two->y(), -100.0); + + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QCOMPARE(three->x(), -100.0); + QCOMPARE(three->y(), -100.0); + + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QCOMPARE(four->x(), -100.0); + QCOMPARE(four->y(), -100.0); + + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + QCOMPARE(five->x(), -100.0); + QCOMPARE(five->y(), -100.0); + + QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn + + QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid"); + QVERIFY(grid); + QCOMPARE(grid->width(), 150.0); + QCOMPARE(grid->height(), 100.0); + + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 157.0); + QCOMPARE(grid->height(), 107.0); + + //QTRY_COMPARE used instead of waiting for the expected time of animation completion + //Note that this means the duration of the animation is NOT tested + + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(one->x(), 103.0); + QTRY_COMPARE(two->isVisible(), false); + QTRY_COMPARE(two->y(), -100.0); + QTRY_COMPARE(two->x(), -100.0); + QTRY_COMPARE(three->y(), 2.0); + QTRY_COMPARE(three->x(), 53.0); + QTRY_COMPARE(four->y(), 2.0); + QTRY_COMPARE(four->x(), 3.0); + QTRY_COMPARE(five->y(), 52.0); + QTRY_COMPARE(five->x(), 103.0); + + //Add 'two' + two->setVisible(true); + QCOMPARE(two->isVisible(), true); + QCOMPARE(grid->width(), 157.0); + QCOMPARE(grid->height(), 107.0); + QTest::qWait(0);//Let the animation start + QCOMPARE(two->x(), -100.0); + QCOMPARE(two->y(), -100.0); + QCOMPARE(one->x(), 103.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(three->x(), 53.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 2.0); + QCOMPARE(five->x(), 103.0); + QCOMPARE(five->y(), 52.0); + //Let the animation complete + QTRY_COMPARE(two->x(), 53.0); + QTRY_COMPARE(two->y(), 2.0); + QTRY_COMPARE(one->x(), 103.0); + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(three->x(), 3.0); + QTRY_COMPARE(three->y(), 2.0); + QTRY_COMPARE(four->x(), 103.0); + QTRY_COMPARE(four->y(), 52.0); + QTRY_COMPARE(five->x(), 53.0); + QTRY_COMPARE(five->y(), 52.0); + +} + void tst_qquickpositioners::test_grid_zero_columns() { QScopedPointer<QQuickView> window(createView(testFile("gridzerocolumns.qml"))); @@ -1395,6 +2644,26 @@ void tst_qquickpositioners::test_grid_zero_columns() QCOMPARE(grid->width(), 170.0); QCOMPARE(grid->height(), 60.0); + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 177.0); + QCOMPARE(grid->height(), 67.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 123.0); + QCOMPARE(four->y(), 2.0); + QCOMPARE(five->x(), 3.0); + QCOMPARE(five->y(), 52.0); } void tst_qquickpositioners::test_grid_H_alignment() @@ -1476,6 +2745,95 @@ void tst_qquickpositioners::test_grid_H_alignment() } +void tst_qquickpositioners::test_grid_H_alignment_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); + + window->rootObject()->setProperty("testHAlignment", QQuickGrid::AlignHCenter); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 50.0); + QCOMPARE(five->x(), 55.0); + QCOMPARE(five->y(), 50.0); + + QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid"); + QCOMPARE(grid->width(), 100.0); + QCOMPARE(grid->height(), 100.0); + + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + + window->rootObject()->setProperty("testHAlignment", QQuickGrid::AlignRight); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 63.0); + QCOMPARE(five->y(), 52.0); + QCOMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + + window->rootObject()->setProperty("testRightToLeft", true); + + QCOMPARE(one->x(), 53.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 33.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 53.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 33.0); + QCOMPARE(five->y(), 52.0); + QCOMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + + window->rootObject()->setProperty("testHAlignment", QQuickGrid::AlignHCenter); + + QCOMPARE(one->x(), 53.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 33.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 2.0); + QCOMPARE(four->x(), 53.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 38.0); + QCOMPARE(five->y(), 52.0); + QCOMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + +} + void tst_qquickpositioners::test_grid_V_alignment() { QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); @@ -1519,6 +2877,63 @@ void tst_qquickpositioners::test_grid_V_alignment() } +void tst_qquickpositioners::test_grid_V_alignment_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); + + window->rootObject()->setProperty("testVAlignment", QQuickGrid::AlignVCenter); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid"); + QCOMPARE(grid->width(), 100.0); + QCOMPARE(grid->height(), 100.0); + + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->width(), 107.0); + QCOMPARE(grid->height(), 107.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 17.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 72.0); + + window->rootObject()->setProperty("testVAlignment", QQuickGrid::AlignBottom); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 73.0); + QCOMPARE(three->y(), 32.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 92.0); + +} + void tst_qquickpositioners::test_propertychanges() { QScopedPointer<QQuickView> window(createView(testFile("propertychangestest.qml"))); @@ -1599,6 +3014,28 @@ void tst_qquickpositioners::test_repeater() } +void tst_qquickpositioners::test_repeater_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("repeatertest-padding.qml"))); + + QQuickRectangle *one = findItem<QQuickRectangle>(window->contentItem(), "one"); + QVERIFY(one != 0); + + QQuickRectangle *two = findItem<QQuickRectangle>(window->contentItem(), "two"); + QVERIFY(two != 0); + + QQuickRectangle *three = findItem<QQuickRectangle>(window->contentItem(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 103.0); + QCOMPARE(three->y(), 2.0); + +} + void tst_qquickpositioners::test_flow() { QScopedPointer<QQuickView> window(createView(testFile("flowtest.qml"))); @@ -1632,6 +3069,219 @@ void tst_qquickpositioners::test_flow() QCOMPARE(flow->width(), 90.0); QCOMPARE(flow->height(), 120.0); + // test padding + flow->setProperty("padding", 1); + flow->setProperty("topPadding", 2); + flow->setProperty("leftPadding", 3); + flow->setProperty("rightPadding", 4); + flow->setProperty("bottomPadding", 5); + + QTRY_COMPARE(flow->height(), 127.0); + QCOMPARE(flow->width(), 90.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 72.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 72.0); +} + +void tst_qquickpositioners::test_flow_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("flowtest.qml"))); + + window->rootObject()->setProperty("testRightToLeft", false); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 50.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 70.0); + QCOMPARE(five->x(), 50.0); + QCOMPARE(five->y(), 70.0); + + QQuickItem *flow = window->rootObject()->findChild<QQuickItem*>("flow"); + QVERIFY(flow); + QCOMPARE(flow->width(), 90.0); + QCOMPARE(flow->height(), 120.0); + + QQuickFlow *obj = qobject_cast<QQuickFlow*>(flow); + QVERIFY(obj != 0); + + QCOMPARE(flow->property("padding").toDouble(), 0.0); + QCOMPARE(flow->property("topPadding").toDouble(), 0.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 0.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 0.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 0.0); + + obj->setPadding(1.0); + + QCOMPARE(flow->property("padding").toDouble(), 1.0); + QCOMPARE(flow->property("topPadding").toDouble(), 1.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 1.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 1.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(flow->height(), 122.0); + QCOMPARE(flow->width(), 90.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 1.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 1.0); + QCOMPARE(three->x(), 1.0); + QCOMPARE(three->y(), 51.0); + QCOMPARE(four->x(), 1.0); + QCOMPARE(four->y(), 71.0); + QCOMPARE(five->x(), 51.0); + QCOMPARE(five->y(), 71.0); + + obj->setTopPadding(2.0); + + QCOMPARE(flow->property("padding").toDouble(), 1.0); + QCOMPARE(flow->property("topPadding").toDouble(), 2.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 1.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 1.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 1.0); + + QTRY_COMPARE(flow->height(), 123.0); + QCOMPARE(flow->width(), 90.0); + + QCOMPARE(one->x(), 1.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 1.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 1.0); + QCOMPARE(four->y(), 72.0); + QCOMPARE(five->x(), 51.0); + QCOMPARE(five->y(), 72.0); + + obj->setLeftPadding(3.0); + + QCOMPARE(flow->property("padding").toDouble(), 1.0); + QCOMPARE(flow->property("topPadding").toDouble(), 2.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 3.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 1.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 1.0); + + QCOMPARE(flow->height(), 123.0); + QCOMPARE(flow->width(), 90.0); + + QTRY_COMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 72.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 72.0); + + obj->setRightPadding(4.0); + + QCOMPARE(flow->property("padding").toDouble(), 1.0); + QCOMPARE(flow->property("topPadding").toDouble(), 2.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 3.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 4.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 1.0); + + QCOMPARE(flow->height(), 123.0); + QCOMPARE(flow->width(), 90.0); + + QTRY_COMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 72.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 72.0); + + obj->setBottomPadding(5.0); + + QCOMPARE(flow->property("padding").toDouble(), 1.0); + QCOMPARE(flow->property("topPadding").toDouble(), 2.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 3.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 4.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 5.0); + + QTRY_COMPARE(flow->height(), 127.0); + QCOMPARE(flow->width(), 90.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 3.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 72.0); + QCOMPARE(five->x(), 53.0); + QCOMPARE(five->y(), 72.0); + + obj->resetBottomPadding(); + QCOMPARE(flow->property("bottomPadding").toDouble(), 1.0); + QTRY_COMPARE(flow->height(), 123.0); + QCOMPARE(flow->width(), 90.0); + + obj->resetRightPadding(); + QCOMPARE(flow->property("rightPadding").toDouble(), 1.0); + QTRY_COMPARE(flow->height(), 123.0); + QCOMPARE(flow->width(), 90.0); + + obj->resetLeftPadding(); + QCOMPARE(flow->property("leftPadding").toDouble(), 1.0); + QTRY_COMPARE(flow->height(), 123.0); + QCOMPARE(flow->width(), 90.0); + + obj->resetTopPadding(); + QCOMPARE(flow->property("topPadding").toDouble(), 1.0); + QTRY_COMPARE(flow->height(), 122.0); + QCOMPARE(flow->width(), 90.0); + + obj->resetPadding(); + QCOMPARE(flow->property("padding").toDouble(), 0.0); + QCOMPARE(flow->property("topPadding").toDouble(), 0.0); + QCOMPARE(flow->property("leftPadding").toDouble(), 0.0); + QCOMPARE(flow->property("rightPadding").toDouble(), 0.0); + QCOMPARE(flow->property("bottomPadding").toDouble(), 0.0); + QTRY_COMPARE(flow->height(), 120.0); + QCOMPARE(flow->width(), 90.0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 50.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 70.0); + QCOMPARE(five->x(), 50.0); + QCOMPARE(five->y(), 70.0); } void tst_qquickpositioners::test_flow_rightToLeft() @@ -1667,6 +3317,26 @@ void tst_qquickpositioners::test_flow_rightToLeft() QCOMPARE(flow->width(), 90.0); QCOMPARE(flow->height(), 120.0); + // test padding + flow->setProperty("padding", 1); + flow->setProperty("topPadding", 2); + flow->setProperty("leftPadding", 3); + flow->setProperty("rightPadding", 4); + flow->setProperty("bottomPadding", 5); + + QTRY_COMPARE(flow->height(), 127.0); + QCOMPARE(flow->width(), 90.0); + + QCOMPARE(one->x(), 36.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 16.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 36.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 36.0); + QCOMPARE(four->y(), 72.0); + QCOMPARE(five->x(), 26.0); + QCOMPARE(five->y(), 72.0); } void tst_qquickpositioners::test_flow_topToBottom() @@ -1693,7 +3363,7 @@ void tst_qquickpositioners::test_flow_topToBottom() QCOMPARE(three->x(), 50.0); QCOMPARE(three->y(), 50.0); QCOMPARE(four->x(), 100.0); - QCOMPARE(four->y(), 00.0); + QCOMPARE(four->y(), 0.0); QCOMPARE(five->x(), 100.0); QCOMPARE(five->y(), 50.0); @@ -1721,6 +3391,79 @@ void tst_qquickpositioners::test_flow_topToBottom() } +void tst_qquickpositioners::test_flow_topToBottom_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("flowtest-toptobottom.qml"))); + + window->rootObject()->setProperty("testRightToLeft", false); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 50.0); + QCOMPARE(three->y(), 50.0); + QCOMPARE(four->x(), 100.0); + QCOMPARE(four->y(), 0.0); + QCOMPARE(five->x(), 100.0); + QCOMPARE(five->y(), 50.0); + + QQuickItem *flow = window->rootObject()->findChild<QQuickItem*>("flow"); + QVERIFY(flow); + QCOMPARE(flow->height(), 90.0); + QCOMPARE(flow->width(), 150.0); + + // test padding + flow->setProperty("padding", 1); + flow->setProperty("topPadding", 2); + flow->setProperty("leftPadding", 3); + flow->setProperty("rightPadding", 4); + flow->setProperty("bottomPadding", 5); + + QTRY_COMPARE(flow->width(), 157.0); + QCOMPARE(flow->height(), 90.0); + + QCOMPARE(one->x(), 3.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 53.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 53.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 103.0); + QCOMPARE(four->y(), 2.0); + QCOMPARE(five->x(), 103.0); + QCOMPARE(five->y(), 52.0); + + window->rootObject()->setProperty("testRightToLeft", true); + + QVERIFY(flow); + QTRY_COMPARE(flow->width(), 157.0); + QCOMPARE(flow->height(), 90.0); + + QCOMPARE(one->x(), 103.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 83.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 53.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 3.0); + QCOMPARE(four->y(), 2.0); + QCOMPARE(five->x(), 43.0); + QCOMPARE(five->y(), 52.0); + +} + void tst_qquickpositioners::test_flow_resize() { QScopedPointer<QQuickView> window(createView(testFile("flowtest.qml"))); @@ -1754,6 +3497,39 @@ void tst_qquickpositioners::test_flow_resize() } +void tst_qquickpositioners::test_flow_resize_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("flowtest-padding.qml"))); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root); + root->setWidth(125); + root->setProperty("testRightToLeft", false); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QVERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QTRY_COMPARE(one->x(), 3.0); + QTRY_COMPARE(one->y(), 2.0); + QTRY_COMPARE(two->x(), 53.0); + QTRY_COMPARE(two->y(), 2.0); + QTRY_COMPARE(three->x(), 3.0); + QTRY_COMPARE(three->y(), 52.0); + QTRY_COMPARE(four->x(), 53.0); + QTRY_COMPARE(four->y(), 52.0); + QTRY_COMPARE(five->x(), 103.0); + QTRY_COMPARE(five->y(), 52.0); + +} + void tst_qquickpositioners::test_flow_resize_rightToLeft() { QScopedPointer<QQuickView> window(createView(testFile("flowtest.qml"))); @@ -1787,6 +3563,39 @@ void tst_qquickpositioners::test_flow_resize_rightToLeft() } +void tst_qquickpositioners::test_flow_resize_rightToLeft_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("flowtest-padding.qml"))); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root); + root->setWidth(125); + root->setProperty("testRightToLeft", true); + + QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); + QTRY_VERIFY(one != 0); + QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); + QVERIFY(two != 0); + QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); + QVERIFY(three != 0); + QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); + QVERIFY(four != 0); + QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 71.0); + QCOMPARE(one->y(), 2.0); + QCOMPARE(two->x(), 51.0); + QCOMPARE(two->y(), 2.0); + QCOMPARE(three->x(), 71.0); + QCOMPARE(three->y(), 52.0); + QCOMPARE(four->x(), 21.0); + QCOMPARE(four->y(), 52.0); + QCOMPARE(five->x(), 11.0); + QCOMPARE(five->y(), 52.0); + +} + void tst_qquickpositioners::test_flow_implicit_resize() { QScopedPointer<QQuickView> window(createView(testFile("flow-testimplicitsize.qml"))); @@ -1815,6 +3624,44 @@ void tst_qquickpositioners::test_flow_implicit_resize() } +void tst_qquickpositioners::test_flow_implicit_resize_padding() +{ + QScopedPointer<QQuickView> window(createView(testFile("flow-testimplicitsize.qml"))); + QVERIFY(window->rootObject() != 0); + + QQuickFlow *flow = window->rootObject()->findChild<QQuickFlow*>("flow"); + QVERIFY(flow != 0); + + QCOMPARE(flow->width(), 100.0); + QCOMPARE(flow->height(), 120.0); + + // test padding + flow->setProperty("padding", 1); + flow->setProperty("topPadding", 2); + flow->setProperty("leftPadding", 3); + flow->setProperty("rightPadding", 4); + flow->setProperty("bottomPadding", 5); + + QTRY_COMPARE(flow->width(), 107.0); + QCOMPARE(flow->height(), 127.0); + + window->rootObject()->setProperty("flowLayout", 0); + QCOMPARE(flow->flow(), QQuickFlow::LeftToRight); + QCOMPARE(flow->width(), 227.0); + QCOMPARE(flow->height(), 57.0); + + window->rootObject()->setProperty("flowLayout", 1); + QCOMPARE(flow->flow(), QQuickFlow::TopToBottom); + QCOMPARE(flow->width(), 107.0); + QCOMPARE(flow->height(), 127.0); + + window->rootObject()->setProperty("flowLayout", 2); + QCOMPARE(flow->layoutDirection(), Qt::RightToLeft); + QCOMPARE(flow->width(), 227.0); + QCOMPARE(flow->height(), 57.0); + +} + void tst_qquickpositioners::test_conflictinganchors() { QQmlTestMessageHandler messageHandler; @@ -1924,7 +3771,9 @@ void tst_qquickpositioners::test_conflictinganchors() void tst_qquickpositioners::test_mirroring() { QList<QString> qmlFiles; - qmlFiles << "horizontal.qml" << "gridtest.qml" << "flowtest.qml"; + qmlFiles << "horizontal.qml" << "horizontal-padding.qml" + << "gridtest.qml" << "gridtest-padding.qml" + << "flowtest.qml" << "flowtest-padding.qml"; QList<QString> objectNames; objectNames << "one" << "two" << "three" << "four" << "five"; @@ -1942,8 +3791,8 @@ void tst_qquickpositioners::test_mirroring() // LTR != RTL foreach (const QString objectName, objectNames) { - // horizontal.qml only has three items - if (qmlFile == QString("horizontal.qml") && objectName == QString("four")) + // horizontal.qml and horizontal-padding.qml only have three items + if (qmlFile.startsWith(QString("horizontal")) && objectName == QString("four")) break; QQuickItem *itemA = rootA->findChild<QQuickItem*>(objectName); QQuickItem *itemB = rootB->findChild<QQuickItem*>(objectName); @@ -1957,8 +3806,8 @@ void tst_qquickpositioners::test_mirroring() // RTL == mirror foreach (const QString objectName, objectNames) { - // horizontal.qml only has three items - if (qmlFile == QString("horizontal.qml") && objectName == QString("four")) + // horizontal.qml and horizontal-padding.qml only have three items + if (qmlFile.startsWith(QString("horizontal")) && objectName == QString("four")) break; QQuickItem *itemA = rootA->findChild<QQuickItem*>(objectName); QQuickItem *itemB = rootB->findChild<QQuickItem*>(objectName); @@ -1978,8 +3827,8 @@ void tst_qquickpositioners::test_mirroring() // LTR == RTL + mirror foreach (const QString objectName, objectNames) { - // horizontal.qml only has three items - if (qmlFile == QString("horizontal.qml") && objectName == QString("four")) + // horizontal.qml and horizontal-padding.qml only have three items + if (qmlFile.startsWith(QString("horizontal")) && objectName == QString("four")) break; QQuickItem *itemA = rootA->findChild<QQuickItem*>(objectName); QQuickItem *itemB = rootB->findChild<QQuickItem*>(objectName); @@ -2000,10 +3849,61 @@ void tst_qquickpositioners::test_allInvisible() QVERIFY(row != 0); QVERIFY(row->width() == 0); QVERIFY(row->height() == 0); + + // test padding + row->setProperty("padding", 1); + row->setProperty("topPadding", 2); + row->setProperty("leftPadding", 3); + row->setProperty("rightPadding", 4); + row->setProperty("bottomPadding", 5); + + QTRY_COMPARE(row->height(), 7.0); + QCOMPARE(row->width(), 7.0); + QQuickColumn *column = window->rootObject()->findChild<QQuickColumn*>("column"); QVERIFY(column != 0); QVERIFY(column->width() == 0); QVERIFY(column->height() == 0); + + // test padding + column->setProperty("padding", 1); + column->setProperty("topPadding", 2); + column->setProperty("leftPadding", 3); + column->setProperty("rightPadding", 4); + column->setProperty("bottomPadding", 5); + + QTRY_COMPARE(column->height(), 7.0); + QCOMPARE(column->width(), 7.0); + + QQuickGrid *grid = window->rootObject()->findChild<QQuickGrid*>("grid"); + QVERIFY(grid != 0); + QVERIFY(grid->width() == 0); + QVERIFY(grid->height() == 0); + + // test padding + grid->setProperty("padding", 1); + grid->setProperty("topPadding", 2); + grid->setProperty("leftPadding", 3); + grid->setProperty("rightPadding", 4); + grid->setProperty("bottomPadding", 5); + + QTRY_COMPARE(grid->height(), 7.0); + QCOMPARE(grid->width(), 7.0); + + QQuickFlow *flow = window->rootObject()->findChild<QQuickFlow*>("flow"); + QVERIFY(flow != 0); + QVERIFY(flow->width() == 0); + QVERIFY(flow->height() == 0); + + // test padding + flow->setProperty("padding", 1); + flow->setProperty("topPadding", 2); + flow->setProperty("leftPadding", 3); + flow->setProperty("rightPadding", 4); + flow->setProperty("bottomPadding", 5); + + QTRY_COMPARE(flow->height(), 7.0); + QCOMPARE(flow->width(), 7.0); } void tst_qquickpositioners::test_attachedproperties() diff --git a/tests/auto/quick/qquickrepeater/data/objectmodel.qml b/tests/auto/quick/qquickrepeater/data/objectmodel.qml new file mode 100644 index 0000000000..780f53e802 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/objectmodel.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 +import QtQml.Models 2.1 + +Row { + width: 360 + height: 360 + + Repeater { + objectName: "repeater" + model: ObjectModel { + Rectangle { + width: 20 + height: 20 + color: "red" + } + Rectangle { + width: 20 + height: 20 + color: "green" + } + Rectangle { + width: 20 + height: 20 + color: "blue" + } + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/stackingorder.qml b/tests/auto/quick/qquickrepeater/data/stackingorder.qml new file mode 100644 index 0000000000..41dadca0df --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/stackingorder.qml @@ -0,0 +1,38 @@ +import QtQuick 2.0 + +Item { + id: root + property bool stackingOrderOk: true + + function verifyStackingOrder() { + var len = children.length + for (var i = 0; i < len; ++i) { + var expectedName; + if (i === 0) { + expectedName = "first" + } else if (i === len - 2) { + expectedName = "repeater" + } else if (i === len - 1) { + expectedName = "last" + } else { + expectedName = "middle" + (i - 1) + } + if (children[i].objectName !== expectedName) + stackingOrderOk = false + } + } + Item { + objectName: "first" + } + Repeater { + objectName: "repeater" + model: 1 + Item { + objectName: "middle" + index + Component.onCompleted: { verifyStackingOrder();} + } + } + Item { + objectName: "last" + } +} diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp index b2039bd323..3d0bb8f1ed 100644 --- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp +++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp @@ -41,6 +41,7 @@ #include <private/qquickrepeater_p.h> #include <QtQuick/private/qquicktext_p.h> #include <QtQml/private/qqmllistmodel_p.h> +#include <QtQml/private/qqmlobjectmodel_p.h> #include "../../shared/util.h" #include "../shared/viewtestutil.h" @@ -76,6 +77,8 @@ private slots: void jsArrayChange(); void clearRemovalOrder(); void destroyCount(); + void stackingOrder(); + void objectModel(); }; class TestObject : public QObject @@ -894,6 +897,82 @@ void tst_QQuickRepeater::destroyCount() QCOMPARE(repeater->property("componentCount").toInt(), 4); } +void tst_QQuickRepeater::stackingOrder() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("stackingorder.qml")); + + QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create()); + QVERIFY(rootObject); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater"); + QVERIFY(repeater); + int count = 1; + do { + bool stackingOrderOk = rootObject->property("stackingOrderOk").toBool(); + QVERIFY(stackingOrderOk); + repeater->setModel(QVariant(++count)); + } while (count < 3); +} + +static bool compareObjectModel(QQuickRepeater *repeater, QQmlObjectModel *model) +{ + if (repeater->count() != model->count()) + return false; + for (int i = 0; i < repeater->count(); ++i) { + if (repeater->itemAt(i) != model->get(i)) + return false; + } + return true; +} + +void tst_QQuickRepeater::objectModel() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("objectmodel.qml")); + + QQuickItem *positioner = qobject_cast<QQuickItem *>(component.create()); + QVERIFY(positioner); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(positioner, "repeater"); + QVERIFY(repeater); + + QQmlObjectModel *model = repeater->model().value<QQmlObjectModel *>(); + QVERIFY(model); + + QVERIFY(repeater->itemAt(0)); + QVERIFY(repeater->itemAt(1)); + QVERIFY(repeater->itemAt(2)); + QCOMPARE(repeater->itemAt(0)->property("color").toString(), QColor("red").name()); + QCOMPARE(repeater->itemAt(1)->property("color").toString(), QColor("green").name()); + QCOMPARE(repeater->itemAt(2)->property("color").toString(), QColor("blue").name()); + + QQuickItem *item0 = new QQuickItem(positioner); + item0->setSize(QSizeF(20, 20)); + model->append(item0); + QCOMPARE(model->count(), 4); + QVERIFY(compareObjectModel(repeater, model)); + + QQuickItem *item1 = new QQuickItem(positioner); + item1->setSize(QSizeF(20, 20)); + model->insert(0, item1); + QCOMPARE(model->count(), 5); + QVERIFY(compareObjectModel(repeater, model)); + + model->move(1, 2, 3); + QVERIFY(compareObjectModel(repeater, model)); + + model->remove(2, 2); + QCOMPARE(model->count(), 3); + QVERIFY(compareObjectModel(repeater, model)); + + model->clear(); + QCOMPARE(model->count(), 0); + QCOMPARE(repeater->count(), 0); + + delete positioner; +} + QTEST_MAIN(tst_QQuickRepeater) #include "tst_qquickrepeater.moc" diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 6c42a7a0ee..4748cd2514 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -1637,7 +1637,7 @@ void tst_qquickstates::QTBUG_38492() void tst_qquickstates::revertListMemoryLeak() { - QWeakPointer<QQmlAbstractBinding> weakPtr; + QQmlAbstractBinding::Ptr bindingPtr; { QQmlEngine engine; @@ -1651,12 +1651,12 @@ void tst_qquickstates::revertListMemoryLeak() QQmlAbstractBinding *binding = state->bindingInRevertList(item, "height"); QVERIFY(binding); - weakPtr = QQmlAbstractBinding::getPointer(binding); - QVERIFY(!weakPtr.toStrongRef().isNull()); + bindingPtr = binding; + QVERIFY(bindingPtr->ref > 1); delete item; } - QVERIFY(weakPtr.toStrongRef().isNull()); + QVERIFY(bindingPtr->ref == 1); } QTEST_MAIN(tst_qquickstates) diff --git a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp index b76218edb9..3c05d4ac73 100644 --- a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp +++ b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp @@ -169,7 +169,7 @@ void tst_qquickstyledtext::textOutput() QCOMPARE(layout.text(), output); - QList<QTextLayout::FormatRange> layoutFormats = layout.additionalFormats(); + const QVector<QTextLayout::FormatRange> layoutFormats = layout.formats(); QCOMPARE(layoutFormats.count(), formats.count()); for (int i = 0; i < formats.count(); ++i) { @@ -198,7 +198,7 @@ void tst_qquickstyledtext::anchors() QCOMPARE(layout.text(), output); - QList<QTextLayout::FormatRange> layoutFormats = layout.additionalFormats(); + const QVector<QTextLayout::FormatRange> layoutFormats = layout.formats(); QCOMPARE(layoutFormats.count(), formats.count()); for (int i = 0; i < formats.count(); ++i) { diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST new file mode 100644 index 0000000000..0c65f1e245 --- /dev/null +++ b/tests/auto/quick/qquicktext/BLACKLIST @@ -0,0 +1,4 @@ +[dependentImplicitSizes] +* +[mouseSelection] +* diff --git a/tests/auto/quick/qquicktext/data/padding.qml b/tests/auto/quick/qquicktext/data/padding.qml new file mode 100644 index 0000000000..ab0a37d041 --- /dev/null +++ b/tests/auto/quick/qquicktext/data/padding.qml @@ -0,0 +1,12 @@ +import QtQuick 2.6 + +Text { + width: 200; height: 200 + text: "Hello Qt" + + padding: 10 + topPadding: 20 + leftPadding: 30 + rightPadding: 40 + bottomPadding: 50 +} diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index eb9f7529fe..c1d454e5df 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -148,6 +148,8 @@ private slots: void growFromZeroWidth(); + void padding(); + private: QStringList standard; QStringList richText; @@ -2048,7 +2050,7 @@ void tst_qquicktext::embeddedImages_data() QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << ""; QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml") << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading {{ServerBaseUrl}}/notexists.png - server replied: Not found"; - QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << ""; + QTest::newRow("remote-relative") << testFileUrl("embeddedImagesRemoteRelative.qml") << ""; } void tst_qquicktext::embeddedImages() @@ -2058,6 +2060,14 @@ void tst_qquicktext::embeddedImages() QFETCH(QUrl, qmlfile); QFETCH(QString, error); +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + if (qstrcmp(QTest::currentDataTag(), "remote") == 0 + || qstrcmp(QTest::currentDataTag(), "remote-error") == 0 + || qstrcmp(QTest::currentDataTag(), "remote-relative") == 0) { + QSKIP("Remote tests cause occasional hangs in the CI system -- QTBUG-45655"); + } +#endif + TestHTTPServer server; QVERIFY2(server.listen(), qPrintable(server.errorString())); server.serveDirectory(testFile("http")); @@ -3634,19 +3644,19 @@ Q_DECLARE_METATYPE(ExpectedBaseline) static qreal expectedBaselineTop(QQuickText *item) { QFontMetricsF fm(item->font()); - return fm.ascent(); + return fm.ascent() + item->topPadding(); } static qreal expectedBaselineBottom(QQuickText *item) { QFontMetricsF fm(item->font()); - return item->height() - item->contentHeight() + fm.ascent(); + return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); } static qreal expectedBaselineCenter(QQuickText *item) { QFontMetricsF fm(item->font()); - return ((item->height() - item->contentHeight()) / 2) + fm.ascent(); + return ((item->height() - item->contentHeight() - item->topPadding() - item->bottomPadding()) / 2) + fm.ascent() + item->topPadding(); } static qreal expectedBaselineBold(QQuickText *item) @@ -3654,7 +3664,7 @@ static qreal expectedBaselineBold(QQuickText *item) QFont font = item->font(); font.setBold(true); QFontMetricsF fm(font); - return fm.ascent(); + return fm.ascent() + item->topPadding(); } static qreal expectedBaselineImage(QQuickText *item) @@ -3664,13 +3674,13 @@ static qreal expectedBaselineImage(QQuickText *item) // or image height - line height and the baseline is line position + ascent. Because // QTextLine's height is rounded up this can give slightly different results to image height // - descent. - return 181 - qCeil(fm.height()) + fm.ascent(); + return 181 - qCeil(fm.height()) + fm.ascent() + item->topPadding(); } static qreal expectedBaselineCustom(QQuickText *item) { QFontMetricsF fm(item->font()); - return 16 + fm.ascent(); + return 16 + fm.ascent() + item->topPadding(); } static qreal expectedBaselineScaled(QQuickText *item) @@ -3689,11 +3699,11 @@ static qreal expectedBaselineScaled(QQuickText *item) if (width < item->width()) { QFontMetricsF fm(layout.font()); - return fm.ascent(); + return fm.ascent() + item->topPadding(); } font.setPointSize(font.pointSize() - 1); } while (font.pointSize() > 0); - return 0; + return item->topPadding(); } static qreal expectedBaselineFixedBottom(QQuickText *item) @@ -3702,7 +3712,7 @@ static qreal expectedBaselineFixedBottom(QQuickText *item) qreal dy = item->text().contains(QLatin1Char('\n')) ? 160 : 180; - return dy + fm.ascent(); + return dy + fm.ascent() - item->bottomPadding(); } static qreal expectedBaselineProportionalBottom(QQuickText *item) @@ -3711,7 +3721,7 @@ static qreal expectedBaselineProportionalBottom(QQuickText *item) qreal dy = item->text().contains(QLatin1Char('\n')) ? 200 - (qCeil(fm.height()) * 3) : 200 - (qCeil(fm.height()) * 1.5); - return dy + fm.ascent(); + return dy + fm.ascent() - item->bottomPadding(); } void tst_qquicktext::baselineOffset_data() @@ -3818,6 +3828,102 @@ void tst_qquicktext::baselineOffset_data() << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom") << &expectedBaselineProportionalBottom << &expectedBaselineProportionalBottom; + + QTest::newRow("top align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; verticalAlignment: Text.AlignTop") + << &expectedBaselineTop + << &expectedBaselineTop; + QTest::newRow("bottom align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; verticalAlignment: Text.AlignBottom") + << &expectedBaselineBottom + << &expectedBaselineBottom; + QTest::newRow("center align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; verticalAlignment: Text.AlignVCenter") + << &expectedBaselineCenter + << &expectedBaselineCenter; + + QTest::newRow("bold width padding") + << "<b>hello world</b>" + << "<b>hello<br/>world</b>" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20") + << &expectedBaselineTop + << &expectedBaselineBold; + + QTest::newRow("richText with padding") + << "<b>hello world</b>" + << "<b>hello<br/>world</b>" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; textFormat: Text.RichText") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("elided with padding") + << "hello world" + << "hello\nworld" + << QByteArray("width: 20; height: 8; topPadding: 10; bottomPadding: 20; elide: Text.ElideRight") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("elided bottom align with padding") + << "hello world" + << "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + << QByteArray("width: 200; height: 200; topPadding: 10; bottomPadding: 20; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom") + << &expectedBaselineBottom + << &expectedBaselineBottom; + + QTest::newRow("image with padding") + << "hello <img src=\"images/heart200.png\" /> world" + << "hello <img src=\"images/heart200.png\" /><br/>world" + << QByteArray("height: 200\n; topPadding: 10; bottomPadding: 20; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"") + << &expectedBaselineImage + << &expectedBaselineTop; + + QTest::newRow("customLine with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; onLineLaidOut: line.y += 16") + << &expectedBaselineCustom + << &expectedBaselineCustom; + + QTest::newRow("scaled font with padding") + << "hello world" + << "hello\nworld" + << QByteArray("width: 200; topPadding: 10; bottomPadding: 20; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit") + << &expectedBaselineScaled + << &expectedBaselineTop; + + QTest::newRow("fixed line height top align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("fixed line height bottom align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom") + << &expectedBaselineFixedBottom + << &expectedBaselineFixedBottom; + + QTest::newRow("proportional line height top align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("proportional line height bottom align with padding") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom") + << &expectedBaselineProportionalBottom + << &expectedBaselineProportionalBottom; } void tst_qquicktext::baselineOffset() @@ -3830,7 +3936,7 @@ void tst_qquicktext::baselineOffset() QQmlComponent component(&engine); component.setData( - "import QtQuick 2.0\n" + "import QtQuick 2.6\n" "Text {\n" + bindings + "\n" "}", QUrl()); @@ -3972,6 +4078,84 @@ void tst_qquicktext::growFromZeroWidth() QVERIFY(text->lineCount() > 3); } +void tst_qquicktext::padding() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("padding.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickText *obj = qobject_cast<QQuickText*>(root); + QVERIFY(obj != 0); + + qreal cw = obj->contentWidth(); + qreal ch = obj->contentHeight(); + + QVERIFY(cw > 0); + QVERIFY(ch > 0); + + QCOMPARE(obj->topPadding(), 20.0); + QCOMPARE(obj->leftPadding(), 30.0); + QCOMPARE(obj->rightPadding(), 40.0); + QCOMPARE(obj->bottomPadding(), 50.0); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setTopPadding(2.25); + QCOMPARE(obj->topPadding(), 2.25); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setLeftPadding(3.75); + QCOMPARE(obj->leftPadding(), 3.75); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setRightPadding(4.4); + QCOMPARE(obj->rightPadding(), 4.4); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setBottomPadding(1.11); + QCOMPARE(obj->bottomPadding(), 1.11); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setText("Qt"); + QVERIFY(obj->contentWidth() < cw); + QCOMPARE(obj->contentHeight(), ch); + cw = obj->contentWidth(); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setFont(QFont("Courier", 96)); + QVERIFY(obj->contentWidth() > cw); + QVERIFY(obj->contentHeight() > ch); + cw = obj->contentWidth(); + ch = obj->contentHeight(); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->resetTopPadding(); + QCOMPARE(obj->topPadding(), 10.0); + obj->resetLeftPadding(); + QCOMPARE(obj->leftPadding(), 10.0); + obj->resetRightPadding(); + QCOMPARE(obj->rightPadding(), 10.0); + obj->resetBottomPadding(); + QCOMPARE(obj->bottomPadding(), 10.0); + + obj->resetPadding(); + QCOMPARE(obj->padding(), 0.0); + QCOMPARE(obj->topPadding(), 0.0); + QCOMPARE(obj->leftPadding(), 0.0); + QCOMPARE(obj->rightPadding(), 0.0); + QCOMPARE(obj->bottomPadding(), 0.0); + + delete root; +} + QTEST_MAIN(tst_qquicktext) #include "tst_qquicktext.moc" diff --git a/tests/auto/quick/qquicktextedit/BLACKLIST b/tests/auto/quick/qquicktextedit/BLACKLIST new file mode 100644 index 0000000000..492d81531a --- /dev/null +++ b/tests/auto/quick/qquicktextedit/BLACKLIST @@ -0,0 +1,2 @@ +[mouseSelection] +* diff --git a/tests/auto/quick/qquicktextedit/data/padding.qml b/tests/auto/quick/qquicktextedit/data/padding.qml new file mode 100644 index 0000000000..f4852bec8b --- /dev/null +++ b/tests/auto/quick/qquicktextedit/data/padding.qml @@ -0,0 +1,12 @@ +import QtQuick 2.6 + +TextEdit { + width: 200; height: 200 + text: "Hello Qt" + + padding: 10 + topPadding: 20 + leftPadding: 30 + rightPadding: 40 + bottomPadding: 50 +} diff --git a/tests/auto/quick/qquicktextedit/data/signal_editingfinished.qml b/tests/auto/quick/qquicktextedit/data/signal_editingfinished.qml new file mode 100644 index 0000000000..b5caab5e7c --- /dev/null +++ b/tests/auto/quick/qquicktextedit/data/signal_editingfinished.qml @@ -0,0 +1,13 @@ +import QtQuick 2.6 + +Item { + property QtObject input1: input1 + property QtObject input2: input2 + + width: 800; height: 600 + + Column{ + TextEdit { id: input1; activeFocusOnTab: true } + TextEdit { id: input2; activeFocusOnTab: true } + } +} diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index 9d1d099c0e..e5c4d0aba5 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -166,6 +166,8 @@ private slots: void implicitSizeBinding_data(); void implicitSizeBinding(); + void signal_editingfinished(); + void preeditCursorRectangle(); void inputMethodComposing(); void cursorRectangleSize_data(); @@ -200,6 +202,8 @@ private slots: void cursorRectangle_QTBUG_38947(); void textCached_QTBUG_41583(); + void padding(); + private: void simulateKeys(QWindow *window, const QList<Key> &keys); void simulateKeys(QWindow *window, const QKeySequence &sequence); @@ -3316,6 +3320,53 @@ void tst_qquicktextedit::implicitSizeBinding() QCOMPARE(textObject->height(), textObject->implicitHeight()); } +void tst_qquicktextedit::signal_editingfinished() +{ + QQuickView *window = new QQuickView(0); + window->setBaseSize(QSize(800,600)); + + window->setSource(testFileUrl("signal_editingfinished.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + QVERIFY(window->rootObject() != 0); + + QQuickTextEdit *input1 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input1"))); + QVERIFY(input1); + QQuickTextEdit *input2 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input2"))); + QVERIFY(input2); + + QSignalSpy editingFinished1Spy(input1, SIGNAL(editingFinished())); + + input1->setFocus(true); + QTRY_VERIFY(input1->hasActiveFocus()); + QTRY_VERIFY(!input2->hasActiveFocus()); + + QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QTRY_COMPARE(editingFinished1Spy.count(), 1); + + QTRY_VERIFY(!input1->hasActiveFocus()); + QTRY_VERIFY(input2->hasActiveFocus()); + + QSignalSpy editingFinished2Spy(input2, SIGNAL(editingFinished())); + + input2->setFocus(true); + QTRY_VERIFY(!input1->hasActiveFocus()); + QTRY_VERIFY(input2->hasActiveFocus()); + + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QTRY_COMPARE(editingFinished2Spy.count(), 1); + + QTRY_VERIFY(input1->hasActiveFocus()); + QTRY_VERIFY(!input2->hasActiveFocus()); +} + void tst_qquicktextedit::clipRect() { QQmlComponent component(&engine); @@ -5323,6 +5374,84 @@ void tst_qquicktextedit::textCached_QTBUG_41583() QVERIFY(!textedit->property("empty").toBool()); } +void tst_qquicktextedit::padding() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("padding.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(root); + QVERIFY(obj != 0); + + qreal cw = obj->contentWidth(); + qreal ch = obj->contentHeight(); + + QVERIFY(cw > 0); + QVERIFY(ch > 0); + + QCOMPARE(obj->topPadding(), 20.0); + QCOMPARE(obj->leftPadding(), 30.0); + QCOMPARE(obj->rightPadding(), 40.0); + QCOMPARE(obj->bottomPadding(), 50.0); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setTopPadding(2.25); + QCOMPARE(obj->topPadding(), 2.25); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setLeftPadding(3.75); + QCOMPARE(obj->leftPadding(), 3.75); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setRightPadding(4.4); + QCOMPARE(obj->rightPadding(), 4.4); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setBottomPadding(1.11); + QCOMPARE(obj->bottomPadding(), 1.11); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setText("Qt"); + QVERIFY(obj->contentWidth() < cw); + QCOMPARE(obj->contentHeight(), ch); + cw = obj->contentWidth(); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setFont(QFont("Courier", 96)); + QVERIFY(obj->contentWidth() > cw); + QVERIFY(obj->contentHeight() > ch); + cw = obj->contentWidth(); + ch = obj->contentHeight(); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->resetTopPadding(); + QCOMPARE(obj->topPadding(), 10.0); + obj->resetLeftPadding(); + QCOMPARE(obj->leftPadding(), 10.0); + obj->resetRightPadding(); + QCOMPARE(obj->rightPadding(), 10.0); + obj->resetBottomPadding(); + QCOMPARE(obj->bottomPadding(), 10.0); + + obj->resetPadding(); + QCOMPARE(obj->padding(), 0.0); + QCOMPARE(obj->topPadding(), 0.0); + QCOMPARE(obj->leftPadding(), 0.0); + QCOMPARE(obj->rightPadding(), 0.0); + QCOMPARE(obj->bottomPadding(), 0.0); + + delete root; +} + QTEST_MAIN(tst_qquicktextedit) #include "tst_qquicktextedit.moc" diff --git a/tests/auto/quick/qquicktextinput/data/padding.qml b/tests/auto/quick/qquicktextinput/data/padding.qml new file mode 100644 index 0000000000..23bfe20f22 --- /dev/null +++ b/tests/auto/quick/qquicktextinput/data/padding.qml @@ -0,0 +1,12 @@ +import QtQuick 2.6 + +TextInput { + width: 200; height: 200 + text: "Hello Qt" + + padding: 10 + topPadding: 20 + leftPadding: 30 + rightPadding: 40 + bottomPadding: 50 +} diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 88cac92864..9ded3870c7 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -45,6 +45,7 @@ #include <QInputMethod> #include <private/qquicktextinput_p.h> #include <private/qquicktextinput_p_p.h> +#include <private/qquickvalidator_p.h> #include <QDebug> #include <QDir> #include <math.h> @@ -222,6 +223,7 @@ private slots: void baselineOffset(); void ensureVisible(); + void padding(); private: void simulateKey(QWindow *, int key); @@ -2996,6 +2998,14 @@ void tst_qquicktextinput::cursorRectangle_data() << false; } +#ifndef QT_NO_IM +#define COMPARE_INPUT_METHOD_QUERY(type, input, property, method, result) \ + QCOMPARE((type) input->inputMethodQuery(property).method(), result); +#else +#define COMPARE_INPUT_METHOD_QUERY(type, input, property, method, result) \ + qt_noop() +#endif + void tst_qquicktextinput::cursorRectangle() { QFETCH(QString, text); @@ -3035,7 +3045,7 @@ void tst_qquicktextinput::cursorRectangle() r = input.cursorRectangle(); QCOMPARE(r.left(), line.cursorToX(i, QTextLine::Leading) - offset); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3045,7 +3055,7 @@ void tst_qquicktextinput::cursorRectangle() for (int i = positionAtWidth + 1; i < text.length(); ++i) { input.setCursorPosition(i); QCOMPARE(r, input.cursorRectangle()); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3058,7 +3068,7 @@ void tst_qquicktextinput::cursorRectangle() } else { QVERIFY(r.left() <= input.width()); } - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3071,7 +3081,7 @@ void tst_qquicktextinput::cursorRectangle() QCOMPARE(r.left(), line.cursorToX(i, QTextLine::Leading) - offset); QCOMPARE(r.top(), 0.); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3083,14 +3093,14 @@ void tst_qquicktextinput::cursorRectangle() QCOMPARE(r.left(), input.width()); } QVERIFY(r.top() >= line.height() - 1); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(11), r); for (int i = wrapPosition + 1; i < text.length(); ++i) { input.setCursorPosition(i); r = input.cursorRectangle(); QVERIFY(r.top() >= line.height() - 1); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3102,7 +3112,7 @@ void tst_qquicktextinput::cursorRectangle() QCOMPARE(r.left(), line.cursorToX(i, QTextLine::Leading) - offset); QCOMPARE(r.top(), 0.); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3112,7 +3122,7 @@ void tst_qquicktextinput::cursorRectangle() for (int i = positionAtWidth + 1; i < wrapPosition && leftToRight; ++i) { input.setCursorPosition(i); QCOMPARE(r, input.cursorRectangle()); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3124,14 +3134,14 @@ void tst_qquicktextinput::cursorRectangle() QCOMPARE(r.left(), input.width()); } QVERIFY(r.bottom() >= input.height()); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(11), r); for (int i = wrapPosition + 1; i < text.length(); ++i) { input.setCursorPosition(i); r = input.cursorRectangle(); QVERIFY(r.bottom() >= input.height()); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3139,7 +3149,7 @@ void tst_qquicktextinput::cursorRectangle() input.setCursorPosition(i); r = input.cursorRectangle(); QVERIFY(r.bottom() >= input.height()); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3147,13 +3157,13 @@ void tst_qquicktextinput::cursorRectangle() r = input.cursorRectangle(); QCOMPARE(r.top(), 0.); QCOMPARE(r.left(), leftToRight ? input.width() : 0); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(10), r); for (int i = wrapPosition - 2; i >= positionAtWidth + 1; --i) { input.setCursorPosition(i); QCOMPARE(r, input.cursorRectangle()); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3161,7 +3171,7 @@ void tst_qquicktextinput::cursorRectangle() input.setCursorPosition(i); r = input.cursorRectangle(); QCOMPARE(r.top(), 0.); - QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRectF(), r); + COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); QCOMPARE(input.positionToRectangle(i), r); } @@ -3230,7 +3240,7 @@ void tst_qquicktextinput::echoMode() //Normal ref &= ~Qt::ImhHiddenText; ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); - QCOMPARE((Qt::InputMethodHints) input->inputMethodQuery(Qt::ImHints).toInt(), ref); + COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); input->setEchoMode(QQuickTextInput::NoEcho); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("")); @@ -3238,17 +3248,17 @@ void tst_qquicktextinput::echoMode() //NoEcho ref |= Qt::ImhHiddenText; ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); - QCOMPARE((Qt::InputMethodHints) input->inputMethodQuery(Qt::ImHints).toInt(), ref); + COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); input->setEchoMode(QQuickTextInput::Password); //Password ref |= Qt::ImhHiddenText; ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QString(8, passwordMaskCharacter.at(0))); - QCOMPARE((Qt::InputMethodHints) input->inputMethodQuery(Qt::ImHints).toInt(), ref); + COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); // clearing input hints do not clear bits set by echo mode input->setInputMethodHints(Qt::ImhNone); - QCOMPARE((Qt::InputMethodHints) input->inputMethodQuery(Qt::ImHints).toInt(), ref); + COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); input->setPasswordCharacter(QChar('Q')); QCOMPARE(input->passwordCharacter(), QLatin1String("Q")); QCOMPARE(input->text(), initial); @@ -3257,19 +3267,20 @@ void tst_qquicktextinput::echoMode() //PasswordEchoOnEdit ref &= ~Qt::ImhHiddenText; ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); - QCOMPARE((Qt::InputMethodHints) input->inputMethodQuery(Qt::ImHints).toInt(), ref); + COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ")); - QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("QQQQQQQQ")); + COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, + QLatin1String("QQQQQQQQ")); QTest::keyPress(&window, Qt::Key_A);//Clearing previous entry is part of PasswordEchoOnEdit QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10); QCOMPARE(input->text(), QLatin1String("a")); QCOMPARE(input->displayText(), QLatin1String("a")); - QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("a")); + COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, QLatin1String("a")); input->setFocus(false); QVERIFY(input->hasActiveFocus() == false); QCOMPARE(input->displayText(), QLatin1String("Q")); - QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("Q")); + COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, QLatin1String("Q")); input->setFocus(true); QVERIFY(input->hasActiveFocus()); QInputMethodEvent inputEvent; @@ -3277,7 +3288,7 @@ void tst_qquicktextinput::echoMode() QGuiApplication::sendEvent(input, &inputEvent); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), initial); - QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial); + COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, initial); } void tst_qquicktextinput::passwordEchoDelay() @@ -6370,25 +6381,25 @@ Q_DECLARE_METATYPE(ExpectedBaseline) static qreal expectedBaselineTop(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return fm.ascent(); + return fm.ascent() + item->topPadding(); } static qreal expectedBaselineBottom(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return item->height() - item->contentHeight() + fm.ascent(); + return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); } static qreal expectedBaselineCenter(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return ((item->height() - item->contentHeight()) / 2) + fm.ascent(); + return ((item->height() - item->contentHeight() - item->topPadding() - item->bottomPadding()) / 2) + fm.ascent() + item->topPadding(); } static qreal expectedBaselineMultilineBottom(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return item->height() - item->contentHeight() + fm.ascent(); + return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); } void tst_qquicktextinput::baselineOffset_data() @@ -6433,6 +6444,41 @@ void tst_qquicktextinput::baselineOffset_data() << -1. << &expectedBaselineMultilineBottom << &expectedBaselineBottom; + + QTest::newRow("padding") + << "Typography" + << QByteArray("topPadding: 10; bottomPadding: 20") + << -1. + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("top align with padding") + << "Typography" + << QByteArray("height: 200; verticalAlignment: Text.AlignTop; topPadding: 10; bottomPadding: 20") + << -1. + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("bottom align with padding") + << "Typography" + << QByteArray("height: 200; verticalAlignment: Text.AlignBottom; topPadding: 10; bottomPadding: 20") + << 100. + << &expectedBaselineBottom + << &expectedBaselineBottom; + + QTest::newRow("center align with padding") + << "Typography" + << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter; topPadding: 10; bottomPadding: 20") + << 100. + << &expectedBaselineCenter + << &expectedBaselineCenter; + + QTest::newRow("multiline bottom aligned with padding") + << "The quick brown fox jumps over the lazy dog" + << QByteArray("height: 200; width: 30; verticalAlignment: Text.AlignBottom; wrapMode: TextInput.WordWrap; topPadding: 10; bottomPadding: 20") + << -1. + << &expectedBaselineMultilineBottom + << &expectedBaselineBottom; } void tst_qquicktextinput::baselineOffset() @@ -6445,7 +6491,7 @@ void tst_qquicktextinput::baselineOffset() QQmlComponent component(&engine); component.setData( - "import QtQuick 2.0\n" + "import QtQuick 2.6\n" "TextInput {\n" + bindings + "\n" "}", QUrl()); @@ -6510,6 +6556,85 @@ void tst_qquicktextinput::ensureVisible() QCOMPARE(input->boundingRect().height(), line.height()); } +void tst_qquicktextinput::padding() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("padding.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickTextInput *obj = qobject_cast<QQuickTextInput*>(root); + QVERIFY(obj != 0); + + qreal cw = obj->contentWidth(); + qreal ch = obj->contentHeight(); + + QVERIFY(cw > 0); + QVERIFY(ch > 0); + + QCOMPARE(obj->padding(), 10.0); + QCOMPARE(obj->topPadding(), 20.0); + QCOMPARE(obj->leftPadding(), 30.0); + QCOMPARE(obj->rightPadding(), 40.0); + QCOMPARE(obj->bottomPadding(), 50.0); + + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setTopPadding(2.25); + QCOMPARE(obj->topPadding(), 2.25); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setLeftPadding(3.75); + QCOMPARE(obj->leftPadding(), 3.75); + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + + obj->setRightPadding(4.4); + QCOMPARE(obj->rightPadding(), 4.4); + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + + obj->setBottomPadding(1.11); + QCOMPARE(obj->bottomPadding(), 1.11); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setText("Qt"); + QVERIFY(obj->contentWidth() < cw); + QCOMPARE(obj->contentHeight(), ch); + cw = obj->contentWidth(); + + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setFont(QFont("Courier", 96)); + QVERIFY(obj->contentWidth() > cw); + QVERIFY(obj->contentHeight() > ch); + cw = obj->contentWidth(); + ch = obj->contentHeight(); + + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->resetTopPadding(); + QCOMPARE(obj->topPadding(), 10.0); + obj->resetLeftPadding(); + QCOMPARE(obj->leftPadding(), 10.0); + obj->resetRightPadding(); + QCOMPARE(obj->rightPadding(), 10.0); + obj->resetBottomPadding(); + QCOMPARE(obj->bottomPadding(), 10.0); + + obj->resetPadding(); + QCOMPARE(obj->padding(), 0.0); + QCOMPARE(obj->topPadding(), 0.0); + QCOMPARE(obj->leftPadding(), 0.0); + QCOMPARE(obj->rightPadding(), 0.0); + QCOMPARE(obj->bottomPadding(), 0.0); + + delete root; +} + QTEST_MAIN(tst_qquicktextinput) #include "tst_qquicktextinput.moc" diff --git a/tests/auto/quick/qquickview/data/error2.qml b/tests/auto/quick/qquickview/data/error2.qml new file mode 100644 index 0000000000..1d754b64f0 --- /dev/null +++ b/tests/auto/quick/qquickview/data/error2.qml @@ -0,0 +1,4 @@ +import QtQuick.Window 2.0 + +Window { +} diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index a980c69140..7ee24bf3d4 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -187,6 +187,15 @@ void tst_QQuickView::errors() QVERIFY(view.status() == QQuickView::Error); QVERIFY(view.errors().count() == 1); } + + { + QQuickView view; + QQmlTestMessageHandler messageHandler; + view.setSource(testFileUrl("error2.qml")); + QVERIFY(view.status() == QQuickView::Error); + QVERIFY(view.errors().count() == 1); + view.show(); + } } void tst_QQuickView::engine() diff --git a/tests/auto/quick/qquickwindow/BLACKLIST b/tests/auto/quick/qquickwindow/BLACKLIST index 1201ef12f0..8a19a679a3 100644 --- a/tests/auto/quick/qquickwindow/BLACKLIST +++ b/tests/auto/quick/qquickwindow/BLACKLIST @@ -1,2 +1,4 @@ +[cursor] +* [testWindowVisibilityOrder] osx diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 93c3a34b39..333c210713 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -504,7 +504,7 @@ void tst_qquickwindow::touchEvent_basic() window->resize(250, 250); window->setPosition(100, 100); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowActive(window)); TestTouchItem *bottomItem = new TestTouchItem(window->contentItem()); bottomItem->setObjectName("Bottom Item"); @@ -635,7 +635,7 @@ void tst_qquickwindow::touchEvent_propagation() window->setPosition(100, 100); window->setTitle(QTest::currentTestFunction()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowActive(window)); TestTouchItem *bottomItem = new TestTouchItem(window->contentItem()); bottomItem->setObjectName("Bottom Item"); @@ -769,18 +769,18 @@ void tst_qquickwindow::touchEvent_cancel() window->setPosition(100, 100); window->setTitle(QTest::currentTestFunction()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowActive(window)); TestTouchItem *item = new TestTouchItem(window->contentItem()); item->setPosition(QPointF(50, 50)); item->setSize(QSizeF(150, 150)); - QPointF pos(10, 10); - QTest::touchEvent(window, touchDevice).press(0, item->mapToScene(pos).toPoint(),window); + QPointF pos(50, 50); + QTest::touchEvent(window, touchDevice).press(0, item->mapToScene(pos).toPoint(), window); QCoreApplication::processEvents(); QTRY_COMPARE(item->lastEvent.touchPoints.count(), 1); - TouchEventData d = makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(item,pos)); + TouchEventData d = makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(item, pos)); COMPARE_TOUCH_DATA(item->lastEvent, d); item->reset(); @@ -803,7 +803,7 @@ void tst_qquickwindow::touchEvent_reentrant() window->setPosition(100, 100); window->setTitle(QTest::currentTestFunction()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowActive(window)); TestTouchItem *item = new TestTouchItem(window->contentItem()); @@ -993,7 +993,7 @@ void tst_qquickwindow::mouseFiltering() window->setPosition(100, 100); window->setTitle(QTest::currentTestFunction()); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowActive(window)); TestTouchItem *bottomItem = new TestTouchItem(window->contentItem()); bottomItem->setObjectName("Bottom Item"); @@ -1452,7 +1452,7 @@ void tst_qquickwindow::cursor() clippedItem.setParentItem(&clippingItem); window.show(); - QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(QTest::qWaitForWindowActive(&window)); // Position the cursor over the parent and child item and the clipped section of clippedItem. QTest::mouseMove(&window, QPoint(100, 100)); @@ -1813,7 +1813,7 @@ void tst_qquickwindow::crashWhenHoverItemDeleted() QVERIFY(!window.isNull()); window->setTitle(QTest::currentTestFunction()); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QTest::qWaitForWindowActive(window.data()); // Simulate a move from the first rectangle to the second. Crash will happen in here // Moving instantaneously from (0, 99) to (0, 102) does not cause the crash @@ -1852,7 +1852,7 @@ void tst_qquickwindow::qobjectEventFilter_touch() window.setPosition(100, 100); window.setTitle(QTest::currentTestFunction()); window.show(); - QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(QTest::qWaitForWindowActive(&window)); TestTouchItem *item = new TestTouchItem(window.contentItem()); item->setSize(QSizeF(150, 150)); @@ -1878,7 +1878,7 @@ void tst_qquickwindow::qobjectEventFilter_key() window.setPosition(100, 100); window.setTitle(QTest::currentTestFunction()); window.show(); - QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(QTest::qWaitForWindowActive(&window)); TestTouchItem *item = new TestTouchItem(window.contentItem()); item->setSize(QSizeF(150, 150)); @@ -1907,8 +1907,7 @@ void tst_qquickwindow::qobjectEventFilter_mouse() window.setPosition(100, 100); window.setTitle(QTest::currentTestFunction()); window.show(); - - QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(QTest::qWaitForWindowActive(&window)); TestTouchItem *item = new TestTouchItem(window.contentItem()); item->setSize(QSizeF(150, 150)); @@ -1917,6 +1916,7 @@ void tst_qquickwindow::qobjectEventFilter_mouse() item->installEventFilter(&eventFilter); QPoint point = item->mapToScene(QPointF(10, 10)).toPoint(); + QTest::mouseMove(&window, point); QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point); QVERIFY(eventFilter.events.contains((int)QEvent::MouseButtonPress)); @@ -2056,44 +2056,108 @@ public: static int deleted; }; +class GlRenderJob : public QRunnable +{ +public: + GlRenderJob(GLubyte *buf) : readPixel(buf), mutex(0), condition(0) {} + ~GlRenderJob() {} + void run() { + QOpenGLContext::currentContext()->functions()->glClearColor(1.0f, 0, 0, 1.0f); + QOpenGLContext::currentContext()->functions()->glClear(GL_COLOR_BUFFER_BIT); + QOpenGLContext::currentContext()->functions()->glReadPixels(0, 0, 1, 1, GL_RGBA, + GL_UNSIGNED_BYTE, + (void *)readPixel); + if (mutex) { + mutex->lock(); + condition->wakeOne(); + mutex->unlock(); + } + } + GLubyte *readPixel; + QMutex *mutex; + QWaitCondition *condition; +}; + int RenderJob::deleted = 0; void tst_qquickwindow::testRenderJob() { QList<QQuickWindow::RenderStage> completedJobs; - QQuickWindow window; - window.setTitle(QTest::currentTestFunction()); - QQuickWindow::RenderStage stages[] = { QQuickWindow::BeforeSynchronizingStage, QQuickWindow::AfterSynchronizingStage, QQuickWindow::BeforeRenderingStage, QQuickWindow::AfterRenderingStage, - QQuickWindow::AfterSwapStage + QQuickWindow::AfterSwapStage, + QQuickWindow::NoStage }; - // Schedule the jobs - for (int i=0; i<5; ++i) - window.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]); - window.show(); - QTRY_COMPARE(completedJobs.size(), 5); + const int numJobs = 6; - for (int i=0; i<5; ++i) { - QCOMPARE(completedJobs.at(i), stages[i]); + { + QQuickWindow window; + window.setTitle(QTest::currentTestFunction()); + RenderJob::deleted = 0; + + // Schedule the jobs + for (int i = 0; i < numJobs; ++i) + window.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + // All jobs should be deleted + QTRY_COMPARE(RenderJob::deleted, numJobs); + + // The NoStage job is not completed, if it is issued when there is no context, + // but the rest will be queued and completed once relevant render stage is hit. + QCOMPARE(completedJobs.size(), numJobs - 1); + + // Verify jobs were completed in correct order + for (int i = 0; i < numJobs - 1; ++i) + QCOMPARE(completedJobs.at(i), stages[i]); + + + // Check that NoStage job gets executed if it is scheduled when window is exposed + completedJobs.clear(); + RenderJob::deleted = 0; + window.scheduleRenderJob(new RenderJob(QQuickWindow::NoStage, &completedJobs), + QQuickWindow::NoStage); + QTRY_COMPARE(RenderJob::deleted, 1); + QCOMPARE(completedJobs.size(), 1); + + // Do a synchronized GL job. + GLubyte readPixel[4] = {0, 0, 0, 0}; + GlRenderJob *glJob = new GlRenderJob(readPixel); + if (window.openglContext()->thread() != QThread::currentThread()) { + QMutex mutex; + QWaitCondition condition; + glJob->mutex = &mutex; + glJob->condition = &condition; + mutex.lock(); + window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + condition.wait(&mutex); + mutex.unlock(); + } else { + window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + } + QCOMPARE(int(readPixel[0]), 255); + QCOMPARE(int(readPixel[1]), 0); + QCOMPARE(int(readPixel[2]), 0); + QCOMPARE(int(readPixel[3]), 255); } - // Verify that jobs are deleted when window has not been rendered at all... + // Verify that jobs are deleted when window is not rendered at all completedJobs.clear(); RenderJob::deleted = 0; { QQuickWindow window2; - for (int i=0; i<5; ++i) { + for (int i = 0; i < numJobs; ++i) { window2.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]); } } + QTRY_COMPARE(RenderJob::deleted, numJobs); QCOMPARE(completedJobs.size(), 0); - QCOMPARE(RenderJob::deleted, 5); } class EventCounter : public QQuickRectangle @@ -2152,7 +2216,7 @@ void tst_qquickwindow::testHoverChildMouseEventFilter() window.setPosition(100, 100); window.setTitle(QTest::currentTestFunction()); window.show(); - QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(QTest::qWaitForWindowActive(&window)); EventCounter *bottomItem = new EventCounter(window.contentItem()); bottomItem->setObjectName("Bottom Item"); diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index c2b7a4cc8d..5593fd94f6 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -74,8 +74,8 @@ QUICKTESTS = \ qquickview \ qquickcanvasitem \ qquickscreen \ - touchmouse - + touchmouse \ + scenegraph SUBDIRS += $$PUBLICTESTS diff --git a/tests/auto/quick/scenegraph/data/mipmap_large.png b/tests/auto/quick/scenegraph/data/mipmap_large.png Binary files differindex 9cb0fc7de1..1b6d99c45c 100644 --- a/tests/auto/quick/scenegraph/data/mipmap_large.png +++ b/tests/auto/quick/scenegraph/data/mipmap_large.png diff --git a/tests/auto/quick/scenegraph/data/mipmap_small.png b/tests/auto/quick/scenegraph/data/mipmap_small.png Binary files differindex dc5216fb6c..2e53012ef5 100644 --- a/tests/auto/quick/scenegraph/data/mipmap_small.png +++ b/tests/auto/quick/scenegraph/data/mipmap_small.png diff --git a/tests/auto/quick/scenegraph/data/render_Mipmap.qml b/tests/auto/quick/scenegraph/data/render_Mipmap.qml index 6d9191c5ac..9bd585373a 100644 --- a/tests/auto/quick/scenegraph/data/render_Mipmap.qml +++ b/tests/auto/quick/scenegraph/data/render_Mipmap.qml @@ -32,6 +32,7 @@ ****************************************************************************/ import QtQuick 2.3 +import QtQuick.Window 2.2 /* The test verifies that scaled down mipmapped images contains @@ -39,8 +40,8 @@ import QtQuick 2.3 #samples: 2 PixelPos R G B Error-tolerance - #final: 0 0 0.33 0.33 0.33 0.1 - #final: 1 0 0.33 0.33 0.33 0.1 + #final: 0 0 0.25 0.25 0.25 0.1 + #final: 1 0 0.25 0.25 0.25 0.1 */ RenderTestBase @@ -52,7 +53,7 @@ RenderTestBase source: "mipmap_small.png" mipmap: true smooth: false - scale: 1 / width; + scale: 1 / (width * Screen.devicePixelRatio); } Image { @@ -62,7 +63,7 @@ RenderTestBase source: "mipmap_large.png" mipmap: true smooth: false - scale: 1 / width; + scale: 1 / (width * Screen.devicePixelRatio); } onEnterFinalStage: finalStageComplete = true; diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index d2d3643ca8..80672e234e 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -33,11 +33,17 @@ #include <qtest.h> +#include <QOffscreenSurface> +#include <QOpenGLContext> +#include <QOpenGLFunctions> + #include <QtQuick> +#include <QtQml> #include <private/qopenglcontext_p.h> +#include <private/qsgcontext_p.h> +#include <private/qsgrenderloop_p.h> -#include <QtQml> class PerPixelRect : public QQuickItem { @@ -97,6 +103,12 @@ private slots: void render(); void hideWithOtherContext(); + + void createTextureFromImage_data(); + void createTextureFromImage(); + +private: + bool m_brokenMipmapSupport; }; template <typename T> class ScopedList : public QList<T> { @@ -107,6 +119,42 @@ public: void tst_SceneGraph::initTestCase() { qmlRegisterType<PerPixelRect>("SceneGraphTest", 1, 0, "PerPixelRect"); + + QSGRenderLoop *loop = QSGRenderLoop::instance(); + qDebug() << "RenderLoop: " << loop; + + QOpenGLContext context; + context.setFormat(loop->sceneGraphContext()->defaultSurfaceFormat()); + context.create(); + QSurfaceFormat format = context.format(); + + QOffscreenSurface surface; + surface.setFormat(format); + surface.create(); + if (!context.makeCurrent(&surface)) + qFatal("Failed to create a GL context..."); + + QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + qDebug() << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); + qDebug() << "Depth Buffer: " << format.depthBufferSize(); + qDebug() << "Stencil Buffer: " << format.stencilBufferSize(); + qDebug() << "Samples: " << format.samples(); + int textureSize; + funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &textureSize); + qDebug() << "Max Texture Size: " << textureSize; + qDebug() << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR); + qDebug() << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER); + QByteArray version = (const char *) funcs->glGetString(GL_VERSION); + qDebug() << "GL_VERSION: " << version.constData(); + QSet<QByteArray> exts = context.extensions(); + QByteArray all; + foreach (const QByteArray &e, exts) all += ' ' + e; + qDebug() << "GL_EXTENSIONS: " << all.constData(); + + m_brokenMipmapSupport = version.contains("Mesa 10.1") || version.contains("Mesa 9."); + qDebug() << "Broken Mipmap: " << m_brokenMipmapSupport; + + context.doneCurrent(); } QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1) @@ -210,7 +258,7 @@ void tst_SceneGraph::manyWindows_data() struct ShareContextResetter { public: - ~ShareContextResetter() { QOpenGLContextPrivate::setGlobalShareContext(0); } + ~ShareContextResetter() { qt_gl_set_global_share_context(0); } }; void tst_SceneGraph::manyWindows() @@ -223,7 +271,7 @@ void tst_SceneGraph::manyWindows() ShareContextResetter cleanup; // To avoid dangling pointer in case of test-failure. if (shared) { QVERIFY(sharedGLContext.create()); - QOpenGLContextPrivate::setGlobalShareContext(&sharedGLContext); + qt_gl_set_global_share_context(&sharedGLContext); } QScopedPointer<QWindow> parent; @@ -297,8 +345,8 @@ struct Sample { .arg(color.redF()).arg(color.greenF()).arg(color.blueF()); } - bool check(const QImage &image) { - QColor color(image.pixel(x, y)); + bool check(const QImage &image, qreal scale) { + QColor color(image.pixel(x * scale, y * scale)); return qAbs(color.redF() - r) <= tolerance && qAbs(color.greenF() - g) <= tolerance && qAbs(color.blueF() - b) <= tolerance; @@ -368,11 +416,11 @@ void tst_SceneGraph::render_data() << "data/render_BreakOpacityBatch.qml" << "data/render_OutOfFloatRange.qml" << "data/render_StackingOrder.qml" - << "data/render_Mipmap.qml" << "data/render_ImageFiltering.qml" << "data/render_bug37422.qml" - << "data/render_OpacityThroughBatchRoot.qml" - ; + << "data/render_OpacityThroughBatchRoot.qml"; + if (!m_brokenMipmapSupport) + files << "data/render_Mipmap.qml"; QRegExp sampleCount("#samples: *(\\d+)"); // X:int Y:int R:float G:float B:float Error:float @@ -428,11 +476,18 @@ void tst_SceneGraph::render() view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); + // We're checking actual pixels, so scale up the sample point to the top-left of the + // 2x2 pixel block and hope that this is good enough. Ideally, view and content + // would be in identical coordinate space, meaning pixels, but we're not in an + // ideal world. + // Just keep this in mind when writing tests. + qreal scale = view.devicePixelRatio(); + // Grab the window and check all our base stage samples QImage content = view.grabWindow(); for (int i=0; i<baseStage.size(); ++i) { Sample sample = baseStage.at(i); - QVERIFY2(sample.check(content), qPrintable(sample.toString(content))); + QVERIFY2(sample.check(content, scale), qPrintable(sample.toString(content))); } // Put the qml file into the final stage and wait for it to @@ -445,7 +500,7 @@ void tst_SceneGraph::render() content = view.grabWindow(); for (int i=0; i<finalStage.size(); ++i) { Sample sample = finalStage.at(i); - QVERIFY2(sample.check(content), qPrintable(sample.toString(content))); + QVERIFY2(sample.check(content, scale), qPrintable(sample.toString(content))); } } @@ -482,6 +537,34 @@ void tst_SceneGraph::hideWithOtherContext() QVERIFY(!renderingOnMainThread || QOpenGLContext::currentContext() != &context); } +void tst_SceneGraph::createTextureFromImage_data() +{ + QImage rgba(64, 64, QImage::Format_ARGB32_Premultiplied); + QImage rgb(64, 64, QImage::Format_RGB32); + + QTest::addColumn<QImage>("image"); + QTest::addColumn<uint>("flags"); + QTest::addColumn<bool>("expectedAlpha"); + + QTest::newRow("rgb") << rgb << uint(0) << false; + QTest::newRow("argb") << rgba << uint(0) << true; + QTest::newRow("rgb,alpha") << rgb << uint(QQuickWindow::TextureHasAlphaChannel) << false; + QTest::newRow("argb,alpha") << rgba << uint(QQuickWindow::TextureHasAlphaChannel) << true; + QTest::newRow("rgb,!alpha") << rgb << uint(QQuickWindow::TextureIsOpaque) << false; + QTest::newRow("argb,!alpha") << rgba << uint(QQuickWindow::TextureIsOpaque) << false; +} + +void tst_SceneGraph::createTextureFromImage() +{ + QFETCH(QImage, image); + QFETCH(uint, flags); + QFETCH(bool, expectedAlpha); + + QQuickView view; + QScopedPointer<QSGTexture> texture(view.createTextureFromImage(image, (QQuickWindow::CreateTextureOptions) flags)); + QCOMPARE(texture->hasAlphaChannel(), expectedAlpha); +} + #include "tst_scenegraph.moc" diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp index 5b9111d448..86d61a0c23 100644 --- a/tests/auto/quick/shared/viewtestutil.cpp +++ b/tests/auto/quick/shared/viewtestutil.cpp @@ -72,18 +72,30 @@ void QQuickViewTestUtil::moveMouseAway(QQuickView *window) #endif } +void QQuickViewTestUtil::moveAndRelease(QQuickView *window, const QPoint &position) +{ + QTest::mouseMove(window, position); + QTest::mouseRelease(window, Qt::LeftButton, 0, position); +} + +void QQuickViewTestUtil::moveAndPress(QQuickView *window, const QPoint &position) +{ + QTest::mouseMove(window, position); + QTest::mousePress(window, Qt::LeftButton, 0, position); +} + void QQuickViewTestUtil::flick(QQuickView *window, const QPoint &from, const QPoint &to, int duration) { const int pointCount = 5; QPoint diff = to - from; // send press, five equally spaced moves, and release. - QTest::mousePress(window, Qt::LeftButton, 0, from); + moveAndPress(window, from); for (int i = 0; i < pointCount; ++i) QTest::mouseMove(window, from + (i+1)*diff/pointCount, duration / pointCount); - QTest::mouseRelease(window, Qt::LeftButton, 0, to); + moveAndRelease(window, to); QTest::qWait(50); } diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h index 8c5f5c54e6..1643eca979 100644 --- a/tests/auto/quick/shared/viewtestutil.h +++ b/tests/auto/quick/shared/viewtestutil.h @@ -48,6 +48,8 @@ namespace QQuickViewTestUtil void centerOnScreen(QQuickView *window, const QSize &size); void centerOnScreen(QQuickView *window); void moveMouseAway(QQuickView *window); + void moveAndPress(QQuickView *window, const QPoint &position); + void moveAndRelease(QQuickView *window, const QPoint &position); QList<int> adjustIndexesForAddDisplaced(const QList<int> &indexes, int index, int count); QList<int> adjustIndexesForMove(const QList<int> &indexes, int from, int to, int count); diff --git a/tests/benchmarks/script/qjsvalue/tst_qjsvalue.cpp b/tests/benchmarks/script/qjsvalue/tst_qjsvalue.cpp index a8e99b5cf9..b5147dbf01 100644 --- a/tests/benchmarks/script/qjsvalue/tst_qjsvalue.cpp +++ b/tests/benchmarks/script/qjsvalue/tst_qjsvalue.cpp @@ -34,12 +34,6 @@ #include <qtest.h> #include <QJSEngine> #include <QJSValue> -#include <private/v8.h> - -QT_BEGIN_NAMESPACE -extern Q_QML_EXPORT v8::Local<v8::Context> qt_QJSEngineV8Context(QJSEngine *); -extern Q_QML_EXPORT v8::Local<v8::Value> qt_QJSValueV8Value(const QJSValue &); -QT_END_NAMESPACE class tst_QJSValue : public QObject { @@ -49,16 +43,12 @@ public: private slots: void fillArray(); - void fillArray_V8(); void property(); - void property_V8(); void setProperty(); - void setProperty_V8(); void call(); - void call_V8(); }; void tst_QJSValue::fillArray() @@ -72,20 +62,6 @@ void tst_QJSValue::fillArray() } } -void tst_QJSValue::fillArray_V8() -{ - QJSEngine eng; - static const int ArrayLength = 10000; - QJSValue array = eng.newArray(ArrayLength); - - v8::HandleScope handleScope; - v8::Local<v8::Array> v8array = qt_QJSValueV8Value(array).As<v8::Array>(); - QBENCHMARK { - for (int i = 0; i < ArrayLength; ++i) - v8array->Set(i, v8::Number::New(i)); - } -} - void tst_QJSValue::property() { QJSEngine eng; @@ -98,23 +74,6 @@ void tst_QJSValue::property() } } -void tst_QJSValue::property_V8() -{ - QJSEngine eng; - QJSValue object = eng.newObject(); - QString propertyName = QString::fromLatin1("foo"); - object.setProperty(propertyName, 123); - QVERIFY(object.property(propertyName).isNumber()); - - v8::HandleScope handleScope; - v8::Local<v8::Object> v8object = qt_QJSValueV8Value(object).As<v8::Object>(); - v8::Local<v8::String> v8propertyName = v8::String::New("foo"); - QVERIFY(v8object->Get(v8propertyName)->IsNumber()); - QBENCHMARK { - v8object->Get(v8propertyName); - } -} - void tst_QJSValue::setProperty() { QJSEngine eng; @@ -126,24 +85,6 @@ void tst_QJSValue::setProperty() } } -void tst_QJSValue::setProperty_V8() -{ - QJSEngine eng; - QJSValue object = eng.newObject(); - - v8::HandleScope handleScope; - // A context scope is needed for v8::Object::Set(), otherwise we crash. - v8::Local<v8::Context> context = qt_QJSEngineV8Context(&eng); - v8::Context::Scope contextScope(context); - - v8::Local<v8::Object> v8object = qt_QJSValueV8Value(object).As<v8::Object>(); - v8::Local<v8::String> v8propertyName = v8::String::New("foo"); - v8::Local<v8::Value> v8value = v8::Number::New(123); - QBENCHMARK { - v8object->Set(v8propertyName, v8value); - } -} - #define TEST_FUNCTION_SOURCE "(function() { return 123; })" void tst_QJSValue::call() @@ -158,24 +99,6 @@ void tst_QJSValue::call() } } -void tst_QJSValue::call_V8() -{ - QJSEngine eng; - QJSValue fun = eng.evaluate(TEST_FUNCTION_SOURCE); - QVERIFY(fun.isCallable()); - - v8::HandleScope handleScope; - v8::Local<v8::Context> context = qt_QJSEngineV8Context(&eng); - v8::Context::Scope contextScope(context); - - v8::Local<v8::Function> v8fun = qt_QJSValueV8Value(fun).As<v8::Function>(); - v8::Local<v8::Object> v8thisObject = v8::Object::New(); - QVERIFY(v8fun->Call(v8thisObject, /*argc=*/0, /*argv=*/0)->IsNumber()); - QBENCHMARK { - v8fun->Call(v8thisObject, /*argc=*/0, /*argv=*/0); - } -} - QTEST_MAIN(tst_QJSValue) #include "tst_qjsvalue.moc" diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 0553553e85..206788c061 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -53,6 +53,7 @@ #include <QFileInfo> #include <QRegularExpression> #include <QStringList> +#include <QScopedPointer> #include <QDebug> #include <QStandardPaths> #include <QTranslator> @@ -67,8 +68,8 @@ #include <cstdlib> #define VERSION_MAJ 1 -#define VERSION_MIN 0 -#define VERSION_STR "1.0" +#define VERSION_MIN 1 +#define VERSION_STR "1.1" #define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms @@ -163,13 +164,20 @@ class LoadWatcher : public QObject public: LoadWatcher(QQmlApplicationEngine *e, int expected) : QObject(e) + , earlyExit(false) , expect(expected) , haveOne(false) { connect(e, SIGNAL(objectCreated(QObject*,QUrl)), this, SLOT(checkFinished(QObject*))); + // QQmlApplicationEngine also connects quit() to QCoreApplication::quit + // but if called before exec() then QCoreApplication::quit does nothing + connect(e, SIGNAL(quit()), + this, SLOT(quit())); } + bool earlyExit; + private: void contain(QObject *o, const QUrl &containPath); void checkForWindow(QObject *o); @@ -196,6 +204,11 @@ public Q_SLOTS: exit(2);//Different return code from qFatal } } + + void quit() { + //Will be checked before calling exec() + earlyExit = true; + } #ifdef QT_GUI_LIB void onOpenGlContextCreated(QOpenGLContext *context); #endif @@ -293,11 +306,10 @@ void printVersion() void printUsage() { - printf("Usage: qml [options] [files]\n"); + printf("Usage: qml [options] [files] [-- args]\n"); printf("\n"); - printf("Any argument ending in .qml will be treated as a QML file to be loaded.\n"); + printf("Any unknown argument before '--' will be treated as a QML file to be loaded.\n"); printf("Any number of QML files can be loaded. They will share the same engine.\n"); - printf("Any argument which is not a recognized option and which does not end in .qml will be ignored.\n"); printf("'gui' application type is only available if the QtGui module is available.\n"); printf("'widget' application type is only available if the QtWidgets module is available.\n"); printf("\n"); @@ -434,8 +446,8 @@ int main(int argc, char *argv[]) app->setOrganizationName("QtProject"); app->setOrganizationDomain("qt-project.org"); - qmlRegisterType<Config>("QmlRuntime.Config", VERSION_MAJ, VERSION_MIN, "Configuration"); - qmlRegisterType<PartialScene>("QmlRuntime.Config", VERSION_MAJ, VERSION_MIN, "PartialScene"); + qmlRegisterType<Config>("QmlRuntime.Config", 1, 0, "Configuration"); + qmlRegisterType<PartialScene>("QmlRuntime.Config", 1, 0, "PartialScene"); QQmlApplicationEngine e; QStringList files; QString confFile; @@ -444,7 +456,7 @@ int main(int argc, char *argv[]) //Handle main arguments QStringList argList = app->arguments(); - for (int i = 0; i < argList.count(); i++) { + for (int i = 1; i < argList.count(); i++) { const QString &arg = argList[i]; if (arg == QLatin1String("-quiet")) quietMode = true; @@ -492,9 +504,7 @@ int main(int argc, char *argv[]) } else if (arg == QLatin1String("-desktop")) { QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); } else { - //If it ends in .qml, treat it as a file. Else ignore it - if (arg.endsWith(".qml")) - files << arg; + files << arg; } } @@ -538,7 +548,7 @@ int main(int argc, char *argv[]) loadConf(confFile, !verboseMode); //Load files - LoadWatcher lw(&e, files.count()); + QScopedPointer<LoadWatcher> lw(new LoadWatcher(&e, files.count())); // Load dummy data before loading QML-files if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir()) @@ -570,6 +580,9 @@ int main(int argc, char *argv[]) } } + if (lw->earlyExit) + return 0; + return app->exec(); } diff --git a/tools/qmleasing/splineeditor.cpp b/tools/qmleasing/splineeditor.cpp index a2ddc056df..b957cab4fe 100644 --- a/tools/qmleasing/splineeditor.cpp +++ b/tools/qmleasing/splineeditor.cpp @@ -680,6 +680,7 @@ void SplineEditor::setEasingCurve(const QString &code) const QStringList stringList = cleanCode.split(QLatin1Char(','), QString::SkipEmptyParts); if (stringList.count() >= 6 && (stringList.count() % 6 == 0)) { QList<qreal> realList; + realList.reserve(stringList.count()); foreach (const QString &string, stringList) { bool ok; realList.append(string.toDouble(&ok)); @@ -687,7 +688,9 @@ void SplineEditor::setEasingCurve(const QString &code) return; } QList<QPointF> points; - for (int i = 0; i < realList.count() / 2; ++i) + const int count = realList.count() / 2; + points.reserve(count); + for (int i = 0; i < count; ++i) points.append(QPointF(realList.at(i * 2), realList.at(i * 2 + 1))); if (points.last() == QPointF(1.0, 1.0)) { QEasingCurve easingCurve(QEasingCurve::BezierSpline); diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index 37f2962a14..beb47e43c1 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -35,7 +35,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qv4codegen_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qqmlpool_p.h> #include <private/qqmlirbuilder_p.h> diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp index db9d1b9cda..53e520cd1f 100644 --- a/tools/qmljs/qmljs.cpp +++ b/tools/qmljs/qmljs.cpp @@ -44,6 +44,7 @@ #include "private/qv4mm_p.h" #include "private/qv4context_p.h" #include "private/qv4script_p.h" +#include "private/qv4string_p.h" #ifdef V4_ENABLE_JIT # include "private/qv4isel_masm_p.h" @@ -72,7 +73,7 @@ struct Print: FunctionObject }; V4_OBJECT(FunctionObject) - static ReturnedValue call(Managed *, CallData *callData) + static ReturnedValue call(const Managed *, CallData *callData) { for (int i = 0; i < callData->argc; ++i) { QString s = callData->args[i].toQStringNoThrow(); @@ -98,9 +99,9 @@ struct GC: public FunctionObject }; V4_OBJECT(FunctionObject) - static ReturnedValue call(Managed *m, CallData *) + static ReturnedValue call(const Managed *m, CallData *) { - static_cast<GC *>(m)->engine()->memoryManager->runGC(); + static_cast<const GC *>(m)->engine()->memoryManager->runGC(); return Encode::undefined(); } }; @@ -113,7 +114,7 @@ static void showException(QV4::ExecutionContext *ctx, const QV4::Value &exceptio { QV4::Scope scope(ctx); QV4::ScopedValue ex(scope, exception); - QV4::ErrorObject *e = ex->asErrorObject(); + QV4::ErrorObject *e = ex->as<QV4::ErrorObject>(); if (!e) { std::cerr << "Uncaught exception: " << qPrintable(ex->toQString()) << std::endl; } else { @@ -187,11 +188,10 @@ int main(int argc, char *argv[]) QV4::Scope scope(&vm); QV4::ScopedContext ctx(scope, vm.rootContext()); - QV4::ScopedObject globalObject(scope, vm.globalObject()); QV4::ScopedObject print(scope, vm.memoryManager->alloc<builtins::Print>(ctx)); - globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("print"))).getPointer(), print); + vm.globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("print"))).getPointer(), print); QV4::ScopedObject gc(scope, vm.memoryManager->alloc<builtins::GC>(ctx)); - globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("gc"))).getPointer(), gc); + vm.globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("gc"))).getPointer(), gc); foreach (const QString &fn, args) { QFile file(fn); diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp index cd81a5bad6..a1161c635a 100644 --- a/tools/qmllint/main.cpp +++ b/tools/qmllint/main.cpp @@ -37,7 +37,7 @@ #include <QCommandLineParser> #include <QCoreApplication> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> #include <private/qqmljsengine_p.h> diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 96c23ae268..c7539ac874 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -685,7 +685,9 @@ private: qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(e.name()))); QList<QPair<QString, QString> > namesValues; - for (int index = 0; index < e.keyCount(); ++index) { + const int keyCount = e.keyCount(); + namesValues.reserve(keyCount); + for (int index = 0; index < keyCount; ++index) { namesValues.append(qMakePair(enquote(QString::fromUtf8(e.key(index))), QString::number(e.value(index)))); } diff --git a/tools/qmlprofiler/commandlistener.cpp b/tools/qmlprofiler/commandlistener.cpp index 1d538d8a3d..369d095725 100644 --- a/tools/qmlprofiler/commandlistener.cpp +++ b/tools/qmlprofiler/commandlistener.cpp @@ -35,24 +35,7 @@ #include "constants.h" #include <QtCore/QTextStream> -CommandListener::CommandListener(QObject *parent) - : QThread(parent) - , m_stopRequested(false) +void CommandListener::readCommand() { -} - -void CommandListener::run() -{ - QString line; - QTextStream in(stdin, QIODevice::ReadOnly); - do { - line = in.readLine(); - line = line.trimmed(); - if (!line.isEmpty()) { - emit command(line); - if (line == QLatin1String(Constants::CMD_QUIT) - || line == QLatin1String(Constants::CMD_QUIT2)) - return; - } - } while (!m_stopRequested && !line.isNull()); + emit command(QTextStream(stdin).readLine()); } diff --git a/tools/qmlprofiler/commandlistener.h b/tools/qmlprofiler/commandlistener.h index 7d4d43d727..e74d5323c8 100644 --- a/tools/qmlprofiler/commandlistener.h +++ b/tools/qmlprofiler/commandlistener.h @@ -36,20 +36,13 @@ #include <QtCore/QThread> -class CommandListener : public QThread -{ +class CommandListener : public QObject { Q_OBJECT -public: - CommandListener(QObject *parent = 0); +public slots: + void readCommand(); - void run(); - - void requestStop() { m_stopRequested = true; } signals: void command(const QString &command); - -private: - bool m_stopRequested; }; #endif // COMMANDLISTENER_H diff --git a/tools/qmlprofiler/constants.h b/tools/qmlprofiler/constants.h index 4e5aac7e32..5b4b52515f 100644 --- a/tools/qmlprofiler/constants.h +++ b/tools/qmlprofiler/constants.h @@ -36,16 +36,27 @@ namespace Constants { -const char CMD_HELP[] ="help"; -const char CMD_HELP2[] = "h"; -const char CMD_HELP3[] = "?"; - const char CMD_RECORD[] ="record"; const char CMD_RECORD2[] ="r"; +const char CMD_OUTPUT[] = "output"; +const char CMD_OUTPUT2[] = "o"; + +const char CMD_FLUSH[] = "flush"; +const char CMD_FLUSH2[] = "f"; + +const char CMD_CLEAR[] = "clear"; +const char CMD_CLEAR2[] = "c"; + const char CMD_QUIT[] ="quit"; const char CMD_QUIT2[] = "q"; +const char CMD_YES[] = "yes"; +const char CMD_YES2[] = "y"; + +const char CMD_NO[] = "no"; +const char CMD_NO2[] = "n"; + } // Constants #endif // CONSTANTS_H diff --git a/tools/qmlprofiler/main.cpp b/tools/qmlprofiler/main.cpp index a1bd1b38b4..12fcc79efa 100644 --- a/tools/qmlprofiler/main.cpp +++ b/tools/qmlprofiler/main.cpp @@ -38,19 +38,23 @@ int main(int argc, char *argv[]) { QmlProfilerApplication app(argc, argv); - if (!app.parseArguments()) { - app.printUsage(); - return 1; - } - - CommandListener listener; - QObject::connect(&listener, SIGNAL(command(QString)), &app, SLOT(userCommand(QString))); - listener.start(); - - int exitValue = app.exec(); - // wait for listener to exit - listener.wait(); + app.parseArguments(); - - return exitValue; + if (app.isInteractive()) { + QThread listenerThread; + CommandListener listener; + listener.moveToThread(&listenerThread); + QObject::connect(&listener, SIGNAL(command(QString)), &app, SLOT(userCommand(QString))); + QObject::connect(&app, SIGNAL(readyForCommand()), &listener, SLOT(readCommand())); + listenerThread.start(); + int exitValue = app.exec(); + listenerThread.quit(); + // wait for listener to exit + listenerThread.wait(); + return exitValue; + } else { + int exitValue = app.exec(); + app.outputData(); + return exitValue; + } } diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp index a51f67164f..8633810790 100644 --- a/tools/qmlprofiler/qmlprofilerapplication.cpp +++ b/tools/qmlprofiler/qmlprofilerapplication.cpp @@ -40,47 +40,49 @@ #include <QtCore/QDateTime> #include <QtCore/QFileInfo> #include <QtCore/QDebug> - -static const char usageTextC[] = -"Usage:\n" -" qmlprofiler [options] [program] [program-options]\n" -" qmlprofiler [options] -attach [hostname]\n" -"\n" -"QML Profiler retrieves QML tracing data from a running application.\n" -"The data collected can then be visualized in Qt Creator.\n" -"\n" -"The application to be profiled has to enable QML debugging. See the Qt Creator\n" -"documentation on how to do this for different Qt versions.\n" -"\n" -"Options:\n" -" -help Show this information and exit.\n" -" -fromStart\n" -" Record as soon as the engine is started, default is false.\n" -" -p <number>, -port <number>\n" -" TCP/IP port to use, default is 3768.\n" -" -v, -verbose\n" -" Print debugging output.\n" -" -version\n" -" Show the version of qmlprofiler and exit.\n"; +#include <QtCore/QCommandLineParser> static const char commandTextC[] = -"Commands:\n" -" r, record\n" -" Switch recording on or off.\n" -" q, quit\n" -" Terminate program."; - -static const char TraceFileExtension[] = ".qtd"; + "The following commands are available:\n" + "'r', 'record'\n" + " Switch recording on or off.\n" + "'o [file]', 'output [file]'\n" + " Output profiling data to <file>. If no <file>\n" + " parameter is given, output to whatever was given\n" + " with --output, or standard output.\n" + "'c', 'clear'\n" + " Clear profiling data recorded so far from memory.\n" + "'f [file]', 'flush [file]'\n" + " Stop recording if it is running, then output the\n" + " data, and finally clear it from memory.\n" + "'q', 'quit'\n" + " Terminate the program if started from qmlprofiler,\n" + " and qmlprofiler itself."; + +static const char *features[] = { + "javascript", + "memory", + "pixmapcache", + "scenegraph", + "animations", + "painting", + "compiling", + "creating", + "binding", + "handlingsignal", + "inputevents" +}; QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) : QCoreApplication(argc, argv), m_runMode(LaunchMode), m_process(0), - m_tracePrefix(QLatin1String("trace")), m_hostName(QLatin1String("127.0.0.1")), m_port(3768), + m_pendingRequest(REQUEST_NONE), m_verbose(false), - m_quitAfterSave(false), + m_recording(true), + m_interactive(false), m_qmlProfilerClient(&m_connection), m_v8profilerClient(&m_connection), m_connectionAttempts(0), @@ -95,11 +97,11 @@ QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) : connect(&m_connection, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError))); connect(&m_qmlProfilerClient, SIGNAL(enabledChanged()), this, SLOT(traceClientEnabled())); - connect(&m_qmlProfilerClient, SIGNAL(recordingChanged(bool)), this, SLOT(recordingChanged())); connect(&m_qmlProfilerClient, SIGNAL(range(QQmlProfilerService::RangeType,QQmlProfilerService::BindingType,qint64,qint64,QStringList,QmlEventLocation)), &m_profilerData, SLOT(addQmlEvent(QQmlProfilerService::RangeType,QQmlProfilerService::BindingType,qint64,qint64,QStringList,QmlEventLocation))); connect(&m_qmlProfilerClient, SIGNAL(traceFinished(qint64)), &m_profilerData, SLOT(setTraceEndTime(qint64))); connect(&m_qmlProfilerClient, SIGNAL(traceStarted(qint64)), &m_profilerData, SLOT(setTraceStartTime(qint64))); + connect(&m_qmlProfilerClient, SIGNAL(traceStarted(qint64)), this, SLOT(notifyTraceStarted())); connect(&m_qmlProfilerClient, SIGNAL(frame(qint64,int,int,int)), &m_profilerData, SLOT(addFrameEvent(qint64,int,int,int))); connect(&m_qmlProfilerClient, SIGNAL(sceneGraphFrame(QQmlProfilerService::SceneGraphFrameType, qint64,qint64,qint64,qint64,qint64,qint64)), @@ -113,6 +115,8 @@ QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) : qint64)), &m_profilerData, SLOT(addMemoryEvent(QQmlProfilerService::MemoryType,qint64, qint64))); + connect(&m_qmlProfilerClient, SIGNAL(inputEvent(QQmlProfilerService::EventType,qint64)), + &m_profilerData, SLOT(addInputEvent(QQmlProfilerService::EventType,qint64))); connect(&m_qmlProfilerClient, SIGNAL(complete()), this, SLOT(qmlComplete())); @@ -140,63 +144,139 @@ QmlProfilerApplication::~QmlProfilerApplication() delete m_process; } -bool QmlProfilerApplication::parseArguments() +void QmlProfilerApplication::parseArguments() { - for (int argPos = 1; argPos < arguments().size(); ++argPos) { - const QString arg = arguments().at(argPos); - if (arg == QLatin1String("-attach") || arg == QLatin1String("-a")) { - if (argPos + 1 == arguments().size()) { - return false; - } - m_hostName = arguments().at(++argPos); - m_runMode = AttachMode; - } else if (arg == QLatin1String("-port") || arg == QLatin1String("-p")) { - if (argPos + 1 == arguments().size()) { - return false; - } - const QString portStr = arguments().at(++argPos); - bool isNumber; - m_port = portStr.toUShort(&isNumber); - if (!isNumber) { - logError(QString("'%1' is not a valid port").arg(portStr)); - return false; - } - } else if (arg == QLatin1String("-fromStart")) { - m_qmlProfilerClient.setRecording(true); - m_v8profilerClient.setRecording(true); - } else if (arg == QLatin1String("-help") || arg == QLatin1String("-h") || arg == QLatin1String("/h") || arg == QLatin1String("/?")) { - return false; - } else if (arg == QLatin1String("-verbose") || arg == QLatin1String("-v")) { - m_verbose = true; - } else if (arg == QLatin1String("-version")) { - print(QString("QML Profiler based on Qt %1.").arg(qVersion())); - ::exit(1); - return false; - } else { - if (m_programPath.isEmpty()) { - m_programPath = arg; - m_tracePrefix = QFileInfo(m_programPath).fileName(); - } else { - m_programArguments << arg; - } + setApplicationName(QLatin1String("qmlprofiler")); + setApplicationVersion(QLatin1String(qVersion())); + + QCommandLineParser parser; + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); + + parser.setApplicationDescription(QChar::LineFeed + tr( + "The QML Profiler retrieves QML tracing data from an application. The data\n" + "collected can then be visualized in Qt Creator. The application to be profiled\n" + "has to enable QML debugging. See the Qt Creator documentation on how to do\n" + "this for different Qt versions.")); + + QCommandLineOption attach(QStringList() << QLatin1String("a") << QLatin1String("attach"), + tr("Attach to an application already running on <hostname>, " + "instead of starting it locally."), + QLatin1String("hostname")); + parser.addOption(attach); + + QCommandLineOption port(QStringList() << QLatin1String("p") << QLatin1String("port"), + tr("Connect to the TCP port <port>. The default is 3768."), + QLatin1String("port"), QLatin1String("3768")); + parser.addOption(port); + + QCommandLineOption output(QStringList() << QLatin1String("o") << QLatin1String("output"), + tr("Save tracing data in <file>. By default the data is sent to the " + "standard output."), QLatin1String("file"), QString()); + parser.addOption(output); + + QCommandLineOption record(QLatin1String("record"), + tr("If set to 'off', don't immediately start recording data when the " + "QML engine starts, but instead either start the recording " + "interactively or with the JavaScript console.profile() function. " + "By default the recording starts immediately."), + QLatin1String("on|off"), QLatin1String("on")); + parser.addOption(record); + + QStringList featureList; + for (int i = 0; i < QQmlProfilerService::MaximumProfileFeature; ++i) + featureList << QLatin1String(features[i]); + + QCommandLineOption include(QLatin1String("include"), + tr("Comma-separated list of features to record. By default all " + "features supported by the QML engine are recorded. If --include " + "is specified, only the given features will be recorded. " + "The following features are unserstood by qmlprofiler: %1").arg( + featureList.join(", ")), + QLatin1String("feature,...")); + parser.addOption(include); + + QCommandLineOption exclude(QLatin1String("exclude"), + tr("Comma-separated list of features to exclude when recording. By " + "default all features supported by the QML engine are recorded. " + "See --include for the features understood by qmlprofiler."), + QLatin1String("feature,...")); + parser.addOption(exclude); + + QCommandLineOption interactive(QLatin1String("interactive"), + tr("Manually control the recording from the command line. The " + "profiler will not terminate itself when the application " + "does so in this case.") + QChar::Space + tr(commandTextC)); + parser.addOption(interactive); + + QCommandLineOption verbose(QStringList() << QLatin1String("verbose"), + tr("Print debugging output.")); + parser.addOption(verbose); + + parser.addHelpOption(); + parser.addVersionOption(); + + parser.addPositionalArgument(QLatin1String("program"), + tr("The program to be started and profiled."), + QLatin1String("[program]")); + parser.addPositionalArgument(QLatin1String("parameters"), + tr("Parameters for the program to be started."), + QLatin1String("[parameters...]")); + + parser.process(*this); + + if (parser.isSet(attach)) { + m_hostName = parser.value(attach); + m_runMode = AttachMode; + } + + if (parser.isSet(port)) { + bool isNumber; + m_port = parser.value(port).toUShort(&isNumber); + if (!isNumber) { + logError(tr("'%1' is not a valid port.").arg(parser.value(port))); + parser.showHelp(1); } } - if (m_runMode == LaunchMode - && m_programPath.isEmpty()) - return false; + m_outputFile = parser.value(output); - if (m_runMode == AttachMode - && !m_programPath.isEmpty()) - return false; + m_recording = (parser.value(record) == QLatin1String("on")); + m_interactive = parser.isSet(interactive); - return true; -} + quint64 features = std::numeric_limits<quint64>::max(); + if (parser.isSet(include)) { + if (parser.isSet(exclude)) { + logError(tr("qmlprofiler can only process either --include or --exclude, not both.")); + parser.showHelp(4); + } + features = parseFeatures(featureList, parser.value(include), false); + } -void QmlProfilerApplication::printUsage() -{ - print(QLatin1String(usageTextC)); - print(QLatin1String(commandTextC)); + if (parser.isSet(exclude)) + features = parseFeatures(featureList, parser.value(exclude), true); + + if (features == 0) + parser.showHelp(4); + + m_qmlProfilerClient.setFeatures(features); + + if (parser.isSet(verbose)) + m_verbose = true; + + m_programArguments = parser.positionalArguments(); + if (!m_programArguments.isEmpty()) + m_programPath = m_programArguments.takeFirst(); + + if (m_runMode == LaunchMode && m_programPath.isEmpty()) { + logError(tr("You have to specify either --attach or a program to start.")); + parser.showHelp(2); + } + + if (m_runMode == AttachMode && !m_programPath.isEmpty()) { + logError(tr("--attach cannot be used when starting a program.")); + parser.showHelp(3); + } } int QmlProfilerApplication::exec() @@ -205,55 +285,189 @@ int QmlProfilerApplication::exec() return QCoreApplication::exec(); } -void QmlProfilerApplication::printCommands() +bool QmlProfilerApplication::isInteractive() const +{ + return m_interactive; +} + +quint64 QmlProfilerApplication::parseFeatures(const QStringList &featureList, const QString &values, + bool exclude) +{ + quint64 features = exclude ? std::numeric_limits<quint64>::max() : 0; + QStringList givenFeatures = values.split(QLatin1Char(',')); + foreach (const QString &f, givenFeatures) { + int index = featureList.indexOf(f); + if (index < 0) { + logError(tr("Unknown feature '%1'").arg(f)); + return 0; + } + quint64 flag = static_cast<quint64>(1) << index; + features = (exclude ? (features ^ flag) : (features | flag)); + } + if (features == 0) { + logError(exclude ? tr("No features remaining to record after processing --exclude.") : + tr("No features specified for --include.")); + } + return features; +} + +void QmlProfilerApplication::flush() { - print(QLatin1String(commandTextC)); + if (m_recording) { + m_pendingRequest = REQUEST_FLUSH; + m_qmlProfilerClient.sendRecordingStatus(false); + m_v8profilerClient.sendRecordingStatus(false); + } else { + if (m_profilerData.save(m_interactiveOutputFile)) { + m_profilerData.clear(); + if (!m_interactiveOutputFile.isEmpty()) + prompt(tr("Data written to %1.").arg(m_interactiveOutputFile)); + else + prompt(); + } else { + prompt(tr("Saving failed.")); + } + m_interactiveOutputFile.clear(); + m_pendingRequest = REQUEST_NONE; + } } -QString QmlProfilerApplication::traceFileName() const +void QmlProfilerApplication::output() { - QString fileName = m_tracePrefix + "_" + - QDateTime::currentDateTime().toString(QLatin1String("yyMMdd_hhmmss")) + - TraceFileExtension; - if (QFileInfo(fileName).exists()) { - QString baseName; - int suffixIndex = 0; - do { - baseName = QFileInfo(fileName).baseName() - + QString::number(suffixIndex++); - } while (QFileInfo(baseName + TraceFileExtension).exists()); - fileName = baseName + TraceFileExtension; + if (m_profilerData.save(m_interactiveOutputFile)) { + if (!m_interactiveOutputFile.isEmpty()) + prompt(tr("Data written to %1.").arg(m_interactiveOutputFile)); + else + prompt(); + } else { + prompt(tr("Saving failed")); } - return QFileInfo(fileName).absoluteFilePath(); + m_interactiveOutputFile.clear(); + m_pendingRequest = REQUEST_NONE; +} + +bool QmlProfilerApplication::checkOutputFile(PendingRequest pending) +{ + if (m_interactiveOutputFile.isEmpty()) + return true; + QFileInfo file(m_interactiveOutputFile); + if (file.exists()) { + if (!file.isFile()) { + prompt(tr("Cannot overwrite %1.").arg(m_interactiveOutputFile)); + m_interactiveOutputFile.clear(); + } else { + prompt(tr("%1 exists. Overwrite (y/n)?").arg(m_interactiveOutputFile)); + m_pendingRequest = pending; + } + return false; + } else { + return true; + } } void QmlProfilerApplication::userCommand(const QString &command) { - QString cmd = command.trimmed(); - if (cmd == Constants::CMD_HELP - || cmd == Constants::CMD_HELP2 - || cmd == Constants::CMD_HELP3) { - printCommands(); - } else if (cmd == Constants::CMD_RECORD - || cmd == Constants::CMD_RECORD2) { - m_qmlProfilerClient.setRecording( - !m_qmlProfilerClient.isRecording()); - m_v8profilerClient.setRecording(!m_v8profilerClient.isRecording()); - m_qmlDataReady = false; - m_v8DataReady = false; - } else if (cmd == Constants::CMD_QUIT - || cmd == Constants::CMD_QUIT2) { - print(QLatin1String("Quit")); - if (m_qmlProfilerClient.isRecording()) { - m_quitAfterSave = true; - m_qmlDataReady = false; - m_v8DataReady = false; - m_qmlProfilerClient.setRecording(false); - m_v8profilerClient.setRecording(false); + QStringList args = command.split(QChar::Space, QString::SkipEmptyParts); + if (args.isEmpty()) { + prompt(); + return; + } + + QByteArray cmd = args.takeFirst().trimmed().toLatin1(); + + if (m_pendingRequest == REQUEST_QUIT) { + if (cmd == Constants::CMD_YES || cmd == Constants::CMD_YES2) { + quit(); + } else if (cmd == Constants::CMD_NO || cmd == Constants::CMD_NO2) { + m_pendingRequest = REQUEST_NONE; + prompt(); + } else { + prompt(tr("The application is still generating data. Really quit (y/n)?")); + } + return; + } + + if (m_pendingRequest == REQUEST_OUTPUT_FILE || m_pendingRequest == REQUEST_FLUSH_FILE) { + if (cmd == Constants::CMD_YES || cmd == Constants::CMD_YES2) { + if (m_pendingRequest == REQUEST_OUTPUT_FILE) + output(); + else + flush(); + } else if (cmd == Constants::CMD_NO || cmd == Constants::CMD_NO2) { + m_pendingRequest = REQUEST_NONE; + m_interactiveOutputFile.clear(); + prompt(); + } else { + prompt(tr("%1 exists. Overwrite (y/n)?")); + } + return; + } + + if (cmd == Constants::CMD_RECORD || cmd == Constants::CMD_RECORD2) { + m_pendingRequest = REQUEST_TOGGLE_RECORDING; + m_qmlProfilerClient.sendRecordingStatus(!m_recording); + m_v8profilerClient.sendRecordingStatus(!m_recording); + } else if (cmd == Constants::CMD_QUIT || cmd == Constants::CMD_QUIT2) { + m_pendingRequest = REQUEST_QUIT; + if (m_recording) { + prompt(tr("The application is still generating data. Really quit (y/n)?")); + } else if (!m_profilerData.isEmpty()) { + prompt(tr("There is still trace data in memory. Really quit (y/n)?")); } else { quit(); } + } else if (cmd == Constants::CMD_OUTPUT || cmd == Constants::CMD_OUTPUT2) { + if (m_recording) { + prompt(tr("Cannot output while recording data.")); + } else if (m_profilerData.isEmpty()) { + prompt(tr("No data was recorded so far.")); + } else { + m_interactiveOutputFile = args.length() > 0 ? args[0] : m_outputFile; + if (checkOutputFile(REQUEST_OUTPUT_FILE)) + output(); + } + } else if (cmd == Constants::CMD_CLEAR || cmd == Constants::CMD_CLEAR2) { + if (m_recording) { + prompt(tr("Cannot clear data while recording.")); + } else if (m_profilerData.isEmpty()) { + prompt(tr("No data was recorded so far.")); + } else { + m_profilerData.clear(); + prompt(tr("Trace data cleared.")); + } + } else if (cmd == Constants::CMD_FLUSH || cmd == Constants::CMD_FLUSH2) { + if (!m_recording && m_profilerData.isEmpty()) { + prompt(tr("No data was recorded so far.")); + } else { + m_interactiveOutputFile = args.length() > 0 ? args[0] : m_outputFile; + if (checkOutputFile(REQUEST_FLUSH_FILE)) + flush(); + } + } else { + prompt(tr(commandTextC)); + } +} + +void QmlProfilerApplication::notifyTraceStarted() +{ + // Synchronize to server state. It doesn't hurt to do this multiple times in a row for + // different traces. There is no symmetric event to "Complete" after all. + m_recording = true; + + if (m_pendingRequest == REQUEST_TOGGLE_RECORDING) { + m_pendingRequest = REQUEST_NONE; + prompt(tr("Recording started")); + } else { + prompt(tr("Application started recording"), false); + } +} + +void QmlProfilerApplication::outputData() +{ + if (!m_profilerData.isEmpty()) { + m_profilerData.save(m_outputFile); + m_profilerData.clear(); } } @@ -304,17 +518,9 @@ void QmlProfilerApplication::tryToConnect() void QmlProfilerApplication::connected() { m_connectTimer.stop(); - print(QString(QLatin1String("Connected to host:port %1:%2." - "Wait for profile data or type a command" - "(type 'help'' to show list of commands).") - ).arg(m_hostName).arg((m_port))); - QString recordingStatus(QLatin1String("Recording Status: %1")); - if (!m_qmlProfilerClient.isRecording() && - !m_v8profilerClient.isRecording()) - recordingStatus = recordingStatus.arg(QLatin1String("Off")); - else - recordingStatus = recordingStatus.arg(QLatin1String("On")); - print(recordingStatus); + prompt(tr("Connected to host:port %1:%2. Wait for profile data or type a command (type 'help' " + "to show list of commands).\nRecording Status: %3") + .arg(m_hostName).arg((m_port)).arg(m_recording ? tr("on") : tr("off"))); } void QmlProfilerApplication::connectionStateChanged( @@ -334,7 +540,7 @@ void QmlProfilerApplication::processHasOutput() { Q_ASSERT(m_process); while (m_process->bytesAvailable()) { - QTextStream out(stdout); + QTextStream out(stderr); out << m_process->readAll(); } } @@ -342,19 +548,19 @@ void QmlProfilerApplication::processHasOutput() void QmlProfilerApplication::processFinished() { Q_ASSERT(m_process); + int exitCode = 0; if (m_process->exitStatus() == QProcess::NormalExit) { logStatus(QString("Process exited (%1).").arg(m_process->exitCode())); - - if (m_qmlProfilerClient.isRecording()) { - logError("Process exited while recording, last trace is lost!"); - exit(2); - } else { - exit(0); + if (m_recording) { + logError("Process exited while recording, last trace is damaged!"); + exitCode = 2; } } else { - logError("Process crashed! Exiting ..."); - exit(3); + logError("Process crashed!"); + exitCode = 3; } + if (!m_interactive) + exit(exitCode); } void QmlProfilerApplication::traceClientEnabled() @@ -362,8 +568,8 @@ void QmlProfilerApplication::traceClientEnabled() logStatus("Trace client is attached."); // blocked server is waiting for recording message from both clients // once the last one is connected, both messages should be sent - m_qmlProfilerClient.sendRecordingStatus(); - m_v8profilerClient.sendRecordingStatus(); + m_qmlProfilerClient.sendRecordingStatus(m_recording); + m_v8profilerClient.sendRecordingStatus(m_recording); } void QmlProfilerApplication::profilerClientEnabled() @@ -372,34 +578,38 @@ void QmlProfilerApplication::profilerClientEnabled() // blocked server is waiting for recording message from both clients // once the last one is connected, both messages should be sent - m_qmlProfilerClient.sendRecordingStatus(); - m_v8profilerClient.sendRecordingStatus(); + m_qmlProfilerClient.sendRecordingStatus(m_recording); + m_v8profilerClient.sendRecordingStatus(m_recording); } void QmlProfilerApplication::traceFinished() { - const QString fileName = traceFileName(); + m_recording = false; // only on "Complete" we know that the trace is really finished. - if (m_profilerData.save(fileName)) - print(QString("Saving trace to %1.").arg(fileName)); + // after receiving both notifications, reset the flags + m_qmlDataReady = false; + m_v8DataReady = false; - if (m_quitAfterSave) - quit(); -} - -void QmlProfilerApplication::recordingChanged() -{ - if (m_qmlProfilerClient.isRecording()) { - print(QLatin1String("Recording is on.")); + if (m_pendingRequest == REQUEST_FLUSH) { + flush(); + } else if (m_pendingRequest == REQUEST_TOGGLE_RECORDING) { + m_pendingRequest = REQUEST_NONE; + prompt(tr("Recording stopped.")); } else { - print(QLatin1String("Recording is off.")); + prompt(tr("Application stopped recording."), false); } } -void QmlProfilerApplication::print(const QString &line) +void QmlProfilerApplication::prompt(const QString &line, bool ready) { - QTextStream err(stderr); - err << line << endl; + if (m_interactive) { + QTextStream err(stderr); + if (!line.isEmpty()) + err << line << endl; + err << QLatin1String("> "); + if (ready) + emit readyForCommand(); + } } void QmlProfilerApplication::logError(const QString &error) @@ -422,8 +632,6 @@ void QmlProfilerApplication::qmlComplete() if (m_v8profilerClient.state() != QQmlDebugClient::Enabled || m_v8DataReady) { m_profilerData.complete(); - // once complete is sent, reset the flag - m_qmlDataReady = false; } } @@ -433,7 +641,5 @@ void QmlProfilerApplication::v8Complete() if (m_qmlProfilerClient.state() != QQmlDebugClient::Enabled || m_qmlDataReady) { m_profilerData.complete(); - // once complete is sent, reset the flag - m_v8DataReady = false; } } diff --git a/tools/qmlprofiler/qmlprofilerapplication.h b/tools/qmlprofiler/qmlprofilerapplication.h index 7e7cebfcf1..f1bf6c3e93 100644 --- a/tools/qmlprofiler/qmlprofilerapplication.h +++ b/tools/qmlprofiler/qmlprofilerapplication.h @@ -41,6 +41,15 @@ #include "qmlprofilerclient.h" #include "qmlprofilerdata.h" +enum PendingRequest { + REQUEST_QUIT, + REQUEST_FLUSH_FILE, + REQUEST_FLUSH, + REQUEST_OUTPUT_FILE, + REQUEST_TOGGLE_RECORDING, + REQUEST_NONE +}; + class QmlProfilerApplication : public QCoreApplication { Q_OBJECT @@ -48,12 +57,17 @@ public: QmlProfilerApplication(int &argc, char **argv); ~QmlProfilerApplication(); - bool parseArguments(); - void printUsage(); + void parseArguments(); int exec(); + bool isInteractive() const; + +signals: + void readyForCommand(); public slots: void userCommand(const QString &command); + void notifyTraceStarted(); + void outputData(); private slots: void run(); @@ -67,9 +81,8 @@ private slots: void traceClientEnabled(); void profilerClientEnabled(); void traceFinished(); - void recordingChanged(); - void print(const QString &line); + void prompt(const QString &line = QString(), bool ready = true); void logError(const QString &error); void logStatus(const QString &status); @@ -77,8 +90,10 @@ private slots: void v8Complete(); private: - void printCommands(); - QString traceFileName() const; + quint64 parseFeatures(const QStringList &featureList, const QString &values, bool exclude); + bool checkOutputFile(PendingRequest pending); + void flush(); + void output(); enum ApplicationMode { LaunchMode, @@ -89,12 +104,16 @@ private: QString m_programPath; QStringList m_programArguments; QProcess *m_process; - QString m_tracePrefix; QString m_hostName; quint16 m_port; + QString m_outputFile; + QString m_interactiveOutputFile; + + PendingRequest m_pendingRequest; bool m_verbose; - bool m_quitAfterSave; + bool m_recording; + bool m_interactive; QQmlDebugConnection m_connection; QmlProfilerClient m_qmlProfilerClient; diff --git a/tools/qmlprofiler/qmlprofilerclient.cpp b/tools/qmlprofiler/qmlprofilerclient.cpp index 711ddbd862..4976a5a0d9 100644 --- a/tools/qmlprofiler/qmlprofilerclient.cpp +++ b/tools/qmlprofiler/qmlprofilerclient.cpp @@ -39,17 +39,12 @@ ProfilerClient::ProfilerClient(const QString &clientName, QQmlDebugConnection *client) : QQmlDebugClient(clientName, client), - m_recording(false), m_enabled(false) { } ProfilerClient::~ProfilerClient() { - //Disable profiling if started by client - //Profiling data will be lost!! - if (isRecording()) - setRecording(false); } void ProfilerClient::clearData() @@ -62,29 +57,6 @@ bool ProfilerClient::isEnabled() const return m_enabled; } -void ProfilerClient::sendRecordingStatus() -{ -} - -bool ProfilerClient::isRecording() const -{ - return m_recording; -} - -void ProfilerClient::setRecording(bool v) -{ - if (v == m_recording) - return; - - m_recording = v; - - if (state() == Enabled) { - sendRecordingStatus(); - } - - emit recordingChanged(v); -} - void ProfilerClient::stateChanged(State status) { if ((m_enabled && status != Enabled) || @@ -99,8 +71,7 @@ class QmlProfilerClientPrivate { public: QmlProfilerClientPrivate() - : inProgressRanges(0) - , maximumTime(0) + : inProgressRanges(0) , features(std::numeric_limits<quint64>::max()) { ::memset(rangeCount, 0, QQmlProfilerService::MaximumRangeType * sizeof(int)); @@ -112,7 +83,8 @@ public: QStack<QmlEventLocation> rangeLocations[QQmlProfilerService::MaximumRangeType]; QStack<QQmlProfilerService::BindingType> bindingTypes; int rangeCount[QQmlProfilerService::MaximumRangeType]; - qint64 maximumTime; + + quint64 features; }; QmlProfilerClient::QmlProfilerClient( @@ -127,6 +99,11 @@ QmlProfilerClient::~QmlProfilerClient() delete d; } +void QmlProfilerClient::setFeatures(quint64 features) +{ + d->features = features; +} + void QmlProfilerClient::clearData() { ::memset(d->rangeCount, 0, @@ -135,19 +112,43 @@ void QmlProfilerClient::clearData() ProfilerClient::clearData(); } -void QmlProfilerClient::sendRecordingStatus() +void QmlProfilerClient::sendRecordingStatus(bool record) { QByteArray ba; QDataStream stream(&ba, QIODevice::WriteOnly); - stream << isRecording(); + stream << record << -1 << d->features; sendMessage(ba); } +inline QQmlProfilerService::ProfileFeature featureFromRangeType( + QQmlProfilerService::RangeType range) +{ + switch (range) { + case QQmlProfilerService::Painting: + return QQmlProfilerService::ProfilePainting; + case QQmlProfilerService::Compiling: + return QQmlProfilerService::ProfileCompiling; + case QQmlProfilerService::Creating: + return QQmlProfilerService::ProfileCreating; + case QQmlProfilerService::Binding: + return QQmlProfilerService::ProfileBinding; + case QQmlProfilerService::HandlingSignal: + return QQmlProfilerService::ProfileHandlingSignal; + case QQmlProfilerService::Javascript: + return QQmlProfilerService::ProfileJavaScript; + default: + return QQmlProfilerService::MaximumProfileFeature; + } +} + void QmlProfilerClient::messageReceived(const QByteArray &data) { QByteArray rwData = data; QDataStream stream(&rwData, QIODevice::ReadOnly); + // Force all the 1 << <FLAG> expressions to be done in 64 bit, to silence some warnings + const quint64 one = static_cast<quint64>(1); + qint64 time; int messageType; @@ -162,25 +163,27 @@ void QmlProfilerClient::messageReceived(const QByteArray &data) if (event == QQmlProfilerService::EndTrace) { emit this->traceFinished(time); - d->maximumTime = time; - d->maximumTime = qMax(time, d->maximumTime); } else if (event == QQmlProfilerService::AnimationFrame) { + if (!(d->features & one << QQmlProfilerService::ProfileAnimations)) + return; int frameRate, animationCount; int threadId = 0; stream >> frameRate >> animationCount; if (!stream.atEnd()) stream >> threadId; emit this->frame(time, frameRate, animationCount, threadId); - d->maximumTime = qMax(time, d->maximumTime); } else if (event == QQmlProfilerService::StartTrace) { emit this->traceStarted(time); - d->maximumTime = time; - } else if (event < QQmlProfilerService::MaximumEventType) { - d->maximumTime = qMax(time, d->maximumTime); + } else if (event == QQmlProfilerService::Key || event == QQmlProfilerService::Mouse) { + if (!(d->features & one << QQmlProfilerService::ProfileInputEvents)) + return; + emit this->inputEvent((QQmlProfilerService::EventType)event, time); } } else if (messageType == QQmlProfilerService::Complete) { emit complete(); } else if (messageType == QQmlProfilerService::SceneGraphFrame) { + if (!(d->features & one << QQmlProfilerService::ProfileSceneGraph)) + return; int sgEventType; int count = 0; qint64 params[5]; @@ -193,8 +196,9 @@ void QmlProfilerClient::messageReceived(const QByteArray &data) params[count++] = 0; emit sceneGraphFrame((QQmlProfilerService::SceneGraphFrameType)sgEventType, time, params[0], params[1], params[2], params[3], params[4]); - d->maximumTime = qMax(time, d->maximumTime); } else if (messageType == QQmlProfilerService::PixmapCacheEvent) { + if (!(d->features & one << QQmlProfilerService::ProfilePixmapCache)) + return; int pixEvTy, width = 0, height = 0, refcount = 0; QString pixUrl; stream >> pixEvTy >> pixUrl; @@ -207,13 +211,13 @@ void QmlProfilerClient::messageReceived(const QByteArray &data) } emit pixmapCache((QQmlProfilerService::PixmapEventType)pixEvTy, time, QmlEventLocation(pixUrl,0,0), width, height, refcount); - d->maximumTime = qMax(time, d->maximumTime); } else if (messageType == QQmlProfilerService::MemoryAllocation) { + if (!(d->features & one << QQmlProfilerService::ProfileMemory)) + return; int type; qint64 delta; stream >> type >> delta; emit memoryAllocation((QQmlProfilerService::MemoryType)type, time, delta); - d->maximumTime = qMax(time, d->maximumTime); } else { int range; stream >> range; @@ -221,6 +225,10 @@ void QmlProfilerClient::messageReceived(const QByteArray &data) if (range >= QQmlProfilerService::MaximumRangeType) return; + if (!(d->features & one << featureFromRangeType( + static_cast<QQmlProfilerService::RangeType>(range)))) + return; + if (messageType == QQmlProfilerService::RangeStart) { d->rangeStartTimes[range].push(time); d->inProgressRanges |= (static_cast<qint64>(1) << range); @@ -263,7 +271,6 @@ void QmlProfilerClient::messageReceived(const QByteArray &data) if (d->inProgressRanges & (static_cast<qint64>(1) << range)) d->inProgressRanges &= ~(static_cast<qint64>(1) << range); - d->maximumTime = qMax(time, d->maximumTime); QStringList data = d->rangeDatas[range].count() ? d->rangeDatas[range].pop() : QStringList(); QmlEventLocation location = d->rangeLocations[range].count() ? @@ -296,19 +303,14 @@ V8ProfilerClient::~V8ProfilerClient() { } -void V8ProfilerClient::sendRecordingStatus() +void V8ProfilerClient::sendRecordingStatus(bool record) { QByteArray ba; QDataStream stream(&ba, QIODevice::WriteOnly); QByteArray cmd("V8PROFILER"); - QByteArray option(""); + QByteArray option(record ? "start" : "stop"); QByteArray title(""); - if (m_recording) { - option = "start"; - } else { - option = "stop"; - } stream << cmd << option << title; sendMessage(ba); } diff --git a/tools/qmlprofiler/qmlprofilerclient.h b/tools/qmlprofiler/qmlprofilerclient.h index 2d9c382ff6..f41ebbd4c9 100644 --- a/tools/qmlprofiler/qmlprofilerclient.h +++ b/tools/qmlprofiler/qmlprofilerclient.h @@ -44,25 +44,18 @@ class ProfilerClient : public QQmlDebugClient Q_OBJECT Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged) - Q_PROPERTY(bool recording READ isRecording WRITE setRecording - NOTIFY recordingChanged) - public: ProfilerClient(const QString &clientName, QQmlDebugConnection *client); ~ProfilerClient(); bool isEnabled() const; - bool isRecording() const; public slots: - void setRecording(bool); virtual void clearData(); - virtual void sendRecordingStatus(); signals: void complete(); - void recordingChanged(bool arg); void enabledChanged(); void cleared(); @@ -70,7 +63,6 @@ protected: virtual void stateChanged(State); protected: - bool m_recording; bool m_enabled; }; @@ -82,9 +74,11 @@ public: QmlProfilerClient(QQmlDebugConnection *client); ~QmlProfilerClient(); + void setFeatures(quint64 features); + public slots: void clearData(); - void sendRecordingStatus(); + void sendRecordingStatus(bool record); signals: void traceFinished( qint64 time ); @@ -101,6 +95,7 @@ signals: void pixmapCache(QQmlProfilerService::PixmapEventType, qint64 time, const QmlEventLocation &location, int width, int height, int refCount); void memoryAllocation(QQmlProfilerService::MemoryType type, qint64 time, qint64 amount); + void inputEvent(QQmlProfilerService::EventType, qint64 time); protected: virtual void messageReceived(const QByteArray &); @@ -125,7 +120,7 @@ public: ~V8ProfilerClient(); public slots: - void sendRecordingStatus(); + void sendRecordingStatus(bool record); signals: void range(int depth, const QString &function, const QString &filename, diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp index c5992652f8..347c51c13b 100644 --- a/tools/qmlprofiler/qmlprofilerdata.cpp +++ b/tools/qmlprofiler/qmlprofilerdata.cpp @@ -177,18 +177,18 @@ QmlProfilerData::~QmlProfilerData() void QmlProfilerData::clear() { - qDeleteAll(d->eventDescriptions.values()); + qDeleteAll(d->eventDescriptions); d->eventDescriptions.clear(); d->startInstanceList.clear(); - qDeleteAll(d->v8EventHash.values()); + qDeleteAll(d->v8EventHash); d->v8EventHash.clear(); d->v8parents.clear(); d->clearV8RootEvent(); d->v8MeasuredTime = 0; - d->traceEndTime = 0; - d->traceStartTime = -1; + d->traceEndTime = std::numeric_limits<qint64>::min(); + d->traceStartTime = std::numeric_limits<qint64>::max(); d->qmlMeasuredTime = 0; setState(Empty); @@ -226,12 +226,14 @@ QString QmlProfilerData::qmlMessageAsString(QQmlProfilerService::Message type) void QmlProfilerData::setTraceStartTime(qint64 time) { - d->traceStartTime = time; + if (time < d->traceStartTime) + d->traceStartTime = time; } void QmlProfilerData::setTraceEndTime(qint64 time) { - d->traceEndTime = time; + if (time > d->traceEndTime) + d->traceEndTime = time; } qint64 QmlProfilerData::traceStartTime() const @@ -388,6 +390,25 @@ void QmlProfilerData::addMemoryEvent(QQmlProfilerService::MemoryType type, qint6 d->startInstanceList.append(rangeEventStartInstance); } +void QmlProfilerData::addInputEvent(QQmlProfilerDefinitions::EventType type, qint64 time) +{ + setState(AcquiringData); + + QString eventHashStr = QString::fromLatin1("Input:%1").arg(type); + + QmlRangeEventData *newEvent; + if (d->eventDescriptions.contains(eventHashStr)) { + newEvent = d->eventDescriptions[eventHashStr]; + } else { + newEvent = new QmlRangeEventData(QString(), type, eventHashStr, QmlEventLocation(), + QString(), QQmlProfilerService::Event, + QQmlProfilerService::MaximumRangeType); + d->eventDescriptions.insert(eventHashStr, newEvent); + } + + d->startInstanceList.append(QmlRangeEventStartInstance(time, -1, 0, 0, 0, newEvent)); +} + QString QmlProfilerData::rootEventName() { return tr("<program>"); @@ -551,10 +572,18 @@ bool QmlProfilerData::save(const QString &filename) return false; } - QFile file(filename); - if (!file.open(QIODevice::WriteOnly)) { - emit error(tr("Could not open %1 for writing").arg(filename)); - return false; + QFile file; + if (!filename.isEmpty()) { + file.setFileName(filename); + if (!file.open(QIODevice::WriteOnly)) { + emit error(tr("Could not open %1 for writing").arg(filename)); + return false; + } + } else { + if (!file.open(stdout, QIODevice::WriteOnly)) { + emit error(tr("Could not open stdout for writing")); + return false; + } } QXmlStreamWriter stream(&file); @@ -589,11 +618,22 @@ bool QmlProfilerData::save(const QString &filename) if (eventData->rangeType == QQmlProfilerService::Binding) stream.writeTextElement(QStringLiteral("bindingType"), QString::number((int)eventData->detailType)); - else if (eventData->message == QQmlProfilerService::Event && - eventData->detailType == QQmlProfilerService::AnimationFrame) - stream.writeTextElement(QStringLiteral("animationFrame"), - QString::number((int)eventData->detailType)); - else if (eventData->message == QQmlProfilerService::PixmapCacheEvent) + else if (eventData->message == QQmlProfilerService::Event) { + switch (eventData->detailType) { + case QQmlProfilerService::AnimationFrame: + stream.writeTextElement(QStringLiteral("animationFrame"), + QString::number((int)eventData->detailType)); + break; + case QQmlProfilerService::Key: + stream.writeTextElement(QStringLiteral("keyEvent"), + QString::number((int)eventData->detailType)); + break; + case QQmlProfilerService::Mouse: + stream.writeTextElement(QStringLiteral("mouseEvent"), + QString::number((int)eventData->detailType)); + break; + } + } else if (eventData->message == QQmlProfilerService::PixmapCacheEvent) stream.writeTextElement(QStringLiteral("cacheEventType"), QString::number((int)eventData->detailType)); else if (eventData->message == QQmlProfilerService::SceneGraphFrame) diff --git a/tools/qmlprofiler/qmlprofilerdata.h b/tools/qmlprofiler/qmlprofilerdata.h index d420275d5e..ef8ef10929 100644 --- a/tools/qmlprofiler/qmlprofilerdata.h +++ b/tools/qmlprofiler/qmlprofilerdata.h @@ -88,6 +88,7 @@ public slots: void addPixmapCacheEvent(QQmlProfilerService::PixmapEventType type, qint64 time, const QmlEventLocation &location, int width, int height, int refcount); void addMemoryEvent(QQmlProfilerService::MemoryType type, qint64 time, qint64 size); + void addInputEvent(QQmlProfilerService::EventType type, qint64 time); void complete(); bool save(const QString &filename); |