Merge remote-tracking branch 'origin/dev' into HEAD

Change-Id: I931a7b264c68c40e16d9467b48173311aef74bd0
This commit is contained in:
Frederik Gladhorn 2016-07-18 15:31:13 +02:00
commit ac79c052af
167 changed files with 4296 additions and 2790 deletions

View File

@ -1,4 +1,4 @@
SOURCES = d3d12.cpp
CONFIG -= qt dylib
CONFIG += console
LIBS += -ldxgi -ld3d12
LIBS += -ldxgi -ld3d12 -ld3dcompiler -ldcomp

View File

@ -754,27 +754,22 @@ bool QQuickLayout::shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&in
d->m_ignoredItems << child;
return ignoreItem;
}
struct QQuickItemPublic : public QQuickItem {
static bool isCompleted(QQuickItem *item) {
return static_cast<QQuickItemPublic*>(item)->isComponentComplete();
}
};
void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
{
if (change == ItemChildAddedChange) {
QQuickItem *item = value.item;
QObject::connect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem()));
QObject::connect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem()));
QObject::connect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem()));
qmlobject_connect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
qmlobject_connect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
if (isReady())
updateLayoutItems();
} else if (change == ItemChildRemovedChange) {
QQuickItem *item = value.item;
QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem()));
QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem()));
QObject::disconnect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
if (isReady())
updateLayoutItems();

View File

@ -333,10 +333,10 @@ QQuickGridLayoutBase::~QQuickGridLayoutBase()
*/
for (int i = 0; i < itemCount(); ++i) {
QQuickItem *item = itemAt(i);
QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed()));
QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged()));
QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem()));
QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickGridLayoutBase, SLOT(invalidateSenderItem()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickGridLayoutBase, SLOT(invalidateSenderItem()));
}
delete d->styleInfo;
}
@ -465,13 +465,13 @@ void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &v
if (change == ItemChildAddedChange) {
quickLayoutDebug() << "ItemChildAddedChange";
QQuickItem *item = value.item;
QObject::connect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed()));
QObject::connect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged()));
qmlobject_connect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
qmlobject_connect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
} else if (change == ItemChildRemovedChange) {
quickLayoutDebug() << "ItemChildRemovedChange";
QQuickItem *item = value.item;
QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed()));
QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
}
QQuickLayout::itemChange(change, value);

View File

@ -711,8 +711,8 @@ Item {
\sa compare(), SignalSpy::wait()
*/
function tryCompare(obj, prop, value, timeout, msg) {
if (arguments.length == 1 || typeof(prop) != "string") {
qtest_results.fail("A property name as string is required for tryCompare",
if (arguments.length == 1 || (typeof(prop) != "string" && typeof(prop) != "number")) {
qtest_results.fail("A property name as string or index is required for tryCompare",
util.callerFile(), util.callerLine())
throw new Error("QtQuickTest::fail")
}

View File

@ -207,7 +207,7 @@ void QQuickCustomParticle::updateVertexShader()
{
m_common.disconnectPropertySignals(this, Key::VertexShader);
m_common.uniformData[Key::VertexShader].clear();
m_common.signalMappers[Key::VertexShader].clear();
m_common.clearSignalMappers(Key::VertexShader);
m_common.attributes.clear();
m_common.attributes.append("qt_ParticlePos");
m_common.attributes.append("qt_ParticleTex");

View File

@ -26,7 +26,8 @@ SOURCES += \
$$PWD/qsgd3d12layer.cpp \
$$PWD/qsgd3d12shadereffectnode.cpp \
$$PWD/qsgd3d12painternode.cpp \
$$PWD/qsgd3d12publicnodes.cpp
$$PWD/qsgd3d12publicnodes.cpp \
$$PWD/qsgd3d12spritenode.cpp
NO_PCH_SOURCES += \
$$PWD/qsgd3d12engine.cpp
@ -50,9 +51,10 @@ HEADERS += \
$$PWD/qsgd3d12layer_p.h \
$$PWD/qsgd3d12shadereffectnode_p.h \
$$PWD/qsgd3d12painternode_p.h \
$$PWD/qsgd3d12publicnodes_p.h
$$PWD/qsgd3d12publicnodes_p.h \
$$PWD/qsgd3d12spritenode_p.h
LIBS += -ldxgi -ld3d12 -ld3dcompiler
LIBS += -ldxgi -ld3d12 -ld3dcompiler -ldcomp
include($$PWD/shaders/shaders.pri)

View File

@ -102,6 +102,7 @@ QSGMaterialType *QSGD3D12VertexColorMaterial::type() const
int QSGD3D12VertexColorMaterial::compare(const QSGMaterial *other) const
{
Q_UNUSED(other);
Q_ASSERT(other && type() == other->type());
// As the vertex color material has all its state in the vertex attributes
// defined by the geometry, all such materials will be equal.
@ -229,6 +230,7 @@ QSGMaterialType *QSGD3D12SmoothColorMaterial::type() const
int QSGD3D12SmoothColorMaterial::compare(const QSGMaterial *other) const
{
Q_UNUSED(other);
Q_ASSERT(other && type() == other->type());
return 0;
}

View File

@ -46,6 +46,8 @@
#include "qsgd3d12shadereffectnode_p.h"
#include "qsgd3d12painternode_p.h"
#include "qsgd3d12publicnodes_p.h"
#include "qsgd3d12spritenode_p.h"
#include <QtQuick/qquickwindow.h>
QT_BEGIN_NAMESPACE
@ -104,7 +106,12 @@ QSize QSGD3D12Context::minimumFBOSize() const
QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const
{
return QSurfaceFormat::defaultFormat();
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
if (QQuickWindow::hasDefaultAlphaBuffer())
format.setAlphaBufferSize(8);
return format;
}
QSGRendererInterface *QSGD3D12Context::rendererInterface(QSGRenderContext *renderContext)
@ -127,4 +134,9 @@ QSGNinePatchNode *QSGD3D12Context::createNinePatchNode()
return new QSGD3D12NinePatchNode;
}
QSGSpriteNode *QSGD3D12Context::createSpriteNode()
{
return new QSGD3D12SpriteNode;
}
QT_END_NAMESPACE

View File

@ -75,6 +75,8 @@ public:
QSGRectangleNode *createRectangleNode() override;
QSGImageNode *createImageNode() override;
QSGNinePatchNode *createNinePatchNode() override;
QSGSpriteNode *createSpriteNode() override;
};
QT_END_NAMESPACE

View File

@ -75,11 +75,14 @@ DECLARE_DEBUG_VAR(render)
Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.general")
// Any changes to the defaults below must be reflected in adaptations.qdoc as
// well and proven by qmlbench or similar.
static const int DEFAULT_SWAP_CHAIN_BUFFER_COUNT = 3;
static const int DEFAULT_FRAME_IN_FLIGHT_COUNT = 2;
static const int DEFAULT_WAITABLE_SWAP_CHAIN_MAX_LATENCY = 0;
static const int MAX_DRAW_CALLS_PER_LIST = 128;
static const int MAX_DRAW_CALLS_PER_LIST = 4096;
static const int MAX_CACHED_ROOTSIG = 16;
static const int MAX_CACHED_PSO = 64;
@ -318,14 +321,14 @@ QSGD3D12Engine::~QSGD3D12Engine()
delete d;
}
bool QSGD3D12Engine::attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples)
bool QSGD3D12Engine::attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha)
{
if (d->isInitialized()) {
qWarning("QSGD3D12Engine: Cannot attach active engine to window");
return false;
}
d->initialize(window, size, dpr, surfaceFormatSamples);
d->initialize(window, size, dpr, surfaceFormatSamples, alpha);
return d->isInitialized();
}
@ -669,6 +672,11 @@ void QSGD3D12EnginePrivate::releaseResources()
commandQueue = nullptr;
copyCommandQueue = nullptr;
dcompTarget = nullptr;
dcompVisual = nullptr;
dcompDevice = nullptr;
swapChain = nullptr;
delete presentFence;
@ -681,7 +689,7 @@ void QSGD3D12EnginePrivate::releaseResources()
// 'window' must be kept, may just be a device loss
}
void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples)
void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha)
{
if (initialized)
return;
@ -690,6 +698,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
windowSize = size;
windowDpr = dpr;
windowSamples = qMax(1, surfaceFormatSamples); // may be -1 or 0, whereas windowSamples is uint and >= 1
windowAlpha = alpha;
swapChainBufferCount = qMin(qEnvironmentVariableIntValue("QT_D3D_BUFFER_COUNT"), MAX_SWAP_CHAIN_BUFFER_COUNT);
if (swapChainBufferCount < 2)
@ -764,28 +773,91 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
#ifndef Q_OS_WINRT
HWND hwnd = reinterpret_cast<HWND>(w);
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = swapChainBufferCount;
swapChainDesc.BufferDesc.Width = windowSize.width() * windowDpr;
swapChainDesc.BufferDesc.Height = windowSize.height() * windowDpr;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
swapChainDesc.Windowed = TRUE;
if (waitableSwapChainMaxLatency)
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
ComPtr<IDXGISwapChain> baseSwapChain;
HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
if (FAILED(hr)) {
qWarning("Failed to create swap chain: 0x%x", hr);
return;
if (windowAlpha) {
// Go through DirectComposition for semi-transparent windows since the
// traditional approaches won't fly with flip model swapchains.
HRESULT hr = DCompositionCreateDevice(nullptr, IID_PPV_ARGS(&dcompDevice));
if (SUCCEEDED(hr)) {
hr = dcompDevice->CreateTargetForHwnd(hwnd, true, &dcompTarget);
if (SUCCEEDED(hr)) {
hr = dcompDevice->CreateVisual(&dcompVisual);
if (FAILED(hr)) {
qWarning("Failed to create DirectComposition visual: 0x%x", hr);
windowAlpha = false;
}
} else {
qWarning("Failed to create DirectComposition target: 0x%x", hr);
windowAlpha = false;
}
} else {
qWarning("Failed to create DirectComposition device: 0x%x", hr);
windowAlpha = false;
}
}
if (FAILED(baseSwapChain.As(&swapChain))) {
qWarning("Failed to cast swap chain");
return;
if (windowAlpha) {
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = windowSize.width() * windowDpr;
swapChainDesc.Height = windowSize.height() * windowDpr;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = swapChainBufferCount;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
if (waitableSwapChainMaxLatency)
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
ComPtr<IDXGISwapChain1> baseSwapChain;
HRESULT hr = dev->dxgi()->CreateSwapChainForComposition(commandQueue.Get(), &swapChainDesc, nullptr, &baseSwapChain);
if (SUCCEEDED(hr)) {
if (SUCCEEDED(baseSwapChain.As(&swapChain))) {
hr = dcompVisual->SetContent(swapChain.Get());
if (SUCCEEDED(hr)) {
hr = dcompTarget->SetRoot(dcompVisual.Get());
if (FAILED(hr)) {
qWarning("SetRoot failed for DirectComposition target: 0x%x", hr);
windowAlpha = false;
}
} else {
qWarning("SetContent failed for DirectComposition visual: 0x%x", hr);
windowAlpha = false;
}
} else {
qWarning("Failed to cast swap chain");
windowAlpha = false;
}
} else {
qWarning("Failed to create swap chain for composition: 0x%x", hr);
windowAlpha = false;
}
}
if (!windowAlpha) {
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = swapChainBufferCount;
swapChainDesc.BufferDesc.Width = windowSize.width() * windowDpr;
swapChainDesc.BufferDesc.Height = windowSize.height() * windowDpr;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
swapChainDesc.Windowed = TRUE;
if (waitableSwapChainMaxLatency)
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
ComPtr<IDXGISwapChain> baseSwapChain;
HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
if (FAILED(hr)) {
qWarning("Failed to create swap chain: 0x%x", hr);
return;
}
if (FAILED(baseSwapChain.As(&swapChain))) {
qWarning("Failed to cast swap chain");
return;
}
}
dev->dxgi()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
@ -810,7 +882,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
return;
}
if (FAILED(baseSwapChain.As(&swapChain))) {
qWarning("Failed to case swap chain");
qWarning("Failed to cast swap chain");
return;
}
@ -1240,7 +1312,7 @@ void QSGD3D12EnginePrivate::updateBuffer(Buffer *buf)
void QSGD3D12EnginePrivate::ensureDevice()
{
if (!initialized && window)
initialize(window, windowSize, windowDpr, windowSamples);
initialize(window, windowSize, windowDpr, windowSamples, windowAlpha);
}
void QSGD3D12EnginePrivate::beginFrame()
@ -2092,6 +2164,11 @@ void QSGD3D12EnginePrivate::present()
return;
}
#ifndef Q_OS_WINRT
if (dcompDevice)
dcompDevice->Commit();
#endif
++presentFrameIndex;
}

View File

@ -287,7 +287,7 @@ public:
QSGD3D12Engine();
~QSGD3D12Engine();
bool attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples);
bool attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha);
void releaseResources();
bool hasResources() const;
void setWindowSize(const QSize &size, float dpr);

View File

@ -56,6 +56,7 @@
#include <d3d12.h>
#include <dxgi1_4.h>
#include <dcomp.h>
#include <wrl/client.h>
using namespace Microsoft::WRL;
@ -130,7 +131,7 @@ struct QSGD3D12CPUWaitableFence
class QSGD3D12EnginePrivate : public QSGD3D12DeviceManager::DeviceLossObserver
{
public:
void initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples);
void initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha);
bool isInitialized() const { return initialized; }
void releaseResources();
void setWindowSize(const QSize &size, float dpr);
@ -269,6 +270,7 @@ private:
QSize windowSize;
float windowDpr;
uint windowSamples;
bool windowAlpha;
int swapChainBufferCount;
int frameInFlightCount;
int waitableSwapChainMaxLatency;
@ -432,6 +434,10 @@ private:
};
DeviceLossTester devLossTest;
ComPtr<IDCompositionDevice> dcompDevice;
ComPtr<IDCompositionTarget> dcompTarget;
ComPtr<IDCompositionVisual> dcompVisual;
};
inline uint qHash(const QSGD3D12EnginePrivate::PersistentFrameData::PendingRelease &pr, uint seed = 0)

View File

@ -115,6 +115,11 @@ QSGRenderer *QSGD3D12RenderContext::createRenderer()
return new QSGD3D12Renderer(this);
}
int QSGD3D12RenderContext::maxTextureSize() const
{
return 16384; // D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
}
void QSGD3D12RenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo)
{
static_cast<QSGD3D12Renderer *>(renderer)->renderScene(fbo);

View File

@ -68,6 +68,7 @@ public:
void renderNextFrame(QSGRenderer *renderer, uint fbo) override;
QSGTexture *createTexture(const QImage &image, uint flags) const override;
QSGRenderer *createRenderer() override;
int maxTextureSize() const override;
void setEngine(QSGD3D12Engine *engine);
QSGD3D12Engine *engine() { return m_engine; }

View File

@ -164,12 +164,13 @@ void QSGD3D12RenderLoop::exposeWindow(QQuickWindow *window)
m_windows[window] = data;
const int samples = window->format().samples();
const bool alpha = window->format().alphaBufferSize() > 0;
const qreal dpr = window->effectiveDevicePixelRatio();
if (Q_UNLIKELY(debug_loop()))
qDebug() << "initializing D3D12 engine" << window << window->size() << dpr << samples;
qDebug() << "initializing D3D12 engine" << window << window->size() << dpr << samples << alpha;
data.engine->attachToWindow(window->winId(), window->size(), dpr, samples);
data.engine->attachToWindow(window->winId(), window->size(), dpr, samples, alpha);
}
void QSGD3D12RenderLoop::obscureWindow(QQuickWindow *window)
@ -289,6 +290,7 @@ void QSGD3D12RenderLoop::releaseResources(QQuickWindow *window)
void QSGD3D12RenderLoop::postJob(QQuickWindow *window, QRunnable *job)
{
Q_UNUSED(window);
Q_ASSERT(job);
Q_ASSERT(window);
job->run();
@ -437,10 +439,11 @@ void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
if (needsWindow) {
// Must only ever get here when there is no window or releaseResources() has been called.
const int samples = window->format().samples();
const bool alpha = window->format().alphaBufferSize() > 0;
const qreal dpr = window->effectiveDevicePixelRatio();
if (Q_UNLIKELY(debug_loop()))
qDebug() << "sync - reinitializing D3D12 engine" << window << window->size() << dpr << samples;
data.engine->attachToWindow(window->winId(), window->size(), dpr, samples);
qDebug() << "sync - reinitializing D3D12 engine" << window << window->size() << dpr << samples << alpha;
data.engine->attachToWindow(window->winId(), window->size(), dpr, samples, alpha);
}
// Recover from device loss.

View File

@ -136,8 +136,7 @@ void QSGD3D12ShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &s
for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
const auto &var(shader.shaderInfo.variables.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
const auto &vd(shader.varData.at(i));
Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Unused);
Q_ASSERT(shader.varData.at(i).specialType == QSGShaderEffectNode::VariableData::Unused);
samplers.insert(var.bindPoint);
}
}

View File

@ -0,0 +1,314 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12spritenode_p.h"
#include "qsgd3d12material_p.h"
#include "vs_sprite.hlslh"
#include "ps_sprite.hlslh"
QT_BEGIN_NAMESPACE
struct SpriteVertex
{
float x;
float y;
float tx;
float ty;
};
struct SpriteVertices
{
SpriteVertex v1;
SpriteVertex v2;
SpriteVertex v3;
SpriteVertex v4;
};
class QSGD3D12SpriteMaterial : public QSGD3D12Material
{
public:
QSGD3D12SpriteMaterial();
~QSGD3D12SpriteMaterial();
QSGMaterialType *type() const override { static QSGMaterialType type; return &type; }
int compare(const QSGMaterial *other) const override
{
return this - static_cast<const QSGD3D12SpriteMaterial *>(other);
}
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
QSGTexture *texture;
float animT;
float animX1;
float animY1;
float animX2;
float animY2;
float animW;
float animH;
};
QSGD3D12SpriteMaterial::QSGD3D12SpriteMaterial()
: texture(nullptr),
animT(0.0f),
animX1(0.0f),
animY1(0.0f),
animX2(0.0f),
animY2(0.0f),
animW(1.0f),
animH(1.0f)
{
setFlag(Blending, true);
}
QSGD3D12SpriteMaterial::~QSGD3D12SpriteMaterial()
{
delete texture;
}
static const int SPRITE_CB_SIZE_0 = 16 * sizeof(float); // float4x4
static const int SPRITE_CB_SIZE_1 = 4 * sizeof(float); // float4
static const int SPRITE_CB_SIZE_2 = 3 * sizeof(float); // float3
static const int SPRITE_CB_SIZE_3 = sizeof(float); // float
static const int SPRITE_CB_SIZE = SPRITE_CB_SIZE_0 + SPRITE_CB_SIZE_1 + SPRITE_CB_SIZE_2 + SPRITE_CB_SIZE_3;
int QSGD3D12SpriteMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(SPRITE_CB_SIZE);
}
void QSGD3D12SpriteMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
pipelineState->shaders.vs = g_VS_Sprite;
pipelineState->shaders.vsSize = sizeof(g_VS_Sprite);
pipelineState->shaders.ps = g_PS_Sprite;
pipelineState->shaders.psSize = sizeof(g_PS_Sprite);
pipelineState->shaders.rootSig.textureViewCount = 1;
}
QSGD3D12Material::UpdateResults QSGD3D12SpriteMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *,
ExtraState *,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = UpdatedConstantBuffer;
quint8 *p = constantBuffer;
if (state.isMatrixDirty())
memcpy(p, state.combinedMatrix().constData(), SPRITE_CB_SIZE_0);
p += SPRITE_CB_SIZE_0;
{
const float v[] = { animX1, animY1, animX2, animY2 };
memcpy(p, v, SPRITE_CB_SIZE_1);
}
p += SPRITE_CB_SIZE_1;
{
const float v[] = { animW, animH, animT };
memcpy(p, v, SPRITE_CB_SIZE_2);
}
p += SPRITE_CB_SIZE_2;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
memcpy(p, &opacity, SPRITE_CB_SIZE_3);
}
texture->bind();
return r;
}
static QSGGeometry::Attribute Sprite_Attributes[] = {
QSGGeometry::Attribute::createWithSemantic(0, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::POSITION),
QSGGeometry::Attribute::createWithSemantic(1, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::TEXCOORD),
};
static QSGGeometry::AttributeSet Sprite_AttributeSet = { 2, 4 * sizeof(float), Sprite_Attributes };
QSGD3D12SpriteNode::QSGD3D12SpriteNode()
: m_material(new QSGD3D12SpriteMaterial)
, m_geometryDirty(true)
, m_sheetSize(QSize(64, 64))
{
m_geometry = new QSGGeometry(Sprite_AttributeSet, 4, 6);
m_geometry->setDrawingMode(QSGGeometry::DrawTriangles);
quint16 *indices = m_geometry->indexDataAsUShort();
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 1;
indices[4] = 3;
indices[5] = 2;
setGeometry(m_geometry);
setMaterial(m_material);
setFlag(OwnsGeometry, true);
setFlag(OwnsMaterial, true);
}
void QSGD3D12SpriteNode::setTexture(QSGTexture *texture)
{
m_material->texture = texture;
m_geometryDirty = true;
markDirty(DirtyMaterial);
}
void QSGD3D12SpriteNode::setTime(float time)
{
m_material->animT = time;
markDirty(DirtyMaterial);
}
void QSGD3D12SpriteNode::setSourceA(const QPoint &source)
{
if (m_sourceA != source) {
m_sourceA = source;
m_material->animX1 = static_cast<float>(source.x()) / m_sheetSize.width();
m_material->animY1 = static_cast<float>(source.y()) / m_sheetSize.height();
markDirty(DirtyMaterial);
}
}
void QSGD3D12SpriteNode::setSourceB(const QPoint &source)
{
if (m_sourceB != source) {
m_sourceB = source;
m_material->animX2 = static_cast<float>(source.x()) / m_sheetSize.width();
m_material->animY2 = static_cast<float>(source.y()) / m_sheetSize.height();
markDirty(DirtyMaterial);
}
}
void QSGD3D12SpriteNode::setSpriteSize(const QSize &size)
{
if (m_spriteSize != size) {
m_spriteSize = size;
m_material->animW = static_cast<float>(size.width()) / m_sheetSize.width();
m_material->animH = static_cast<float>(size.height()) / m_sheetSize.height();
markDirty(DirtyMaterial);
}
}
void QSGD3D12SpriteNode::setSheetSize(const QSize &size)
{
if (m_sheetSize != size) {
m_sheetSize = size;
// Update all dependent properties
m_material->animX1 = static_cast<float>(m_sourceA.x()) / m_sheetSize.width();
m_material->animY1 = static_cast<float>(m_sourceA.y()) / m_sheetSize.height();
m_material->animX2 = static_cast<float>(m_sourceB.x()) / m_sheetSize.width();
m_material->animY2 = static_cast<float>(m_sourceB.y()) / m_sheetSize.height();
m_material->animW = static_cast<float>(m_spriteSize.width()) / m_sheetSize.width();
m_material->animH = static_cast<float>(m_spriteSize.height()) / m_sheetSize.height();
markDirty(DirtyMaterial);
}
}
void QSGD3D12SpriteNode::setSize(const QSizeF &size)
{
if (m_size != size) {
m_size = size;
m_geometryDirty = true;
}
}
void QSGD3D12SpriteNode::setFiltering(QSGTexture::Filtering filtering)
{
m_material->texture->setFiltering(filtering);
markDirty(DirtyMaterial);
}
void QSGD3D12SpriteNode::update()
{
if (m_geometryDirty) {
m_geometryDirty = false;
updateGeometry();
}
}
void QSGD3D12SpriteNode::updateGeometry()
{
if (!m_material->texture)
return;
SpriteVertices *p = static_cast<SpriteVertices *>(m_geometry->vertexData());
const QRectF texRect = m_material->texture->normalizedTextureSubRect();
p->v1.tx = texRect.topLeft().x();
p->v1.ty = texRect.topLeft().y();
p->v2.tx = texRect.topRight().x();
p->v2.ty = texRect.topRight().y();
p->v3.tx = texRect.bottomLeft().x();
p->v3.ty = texRect.bottomLeft().y();
p->v4.tx = texRect.bottomRight().x();
p->v4.ty = texRect.bottomRight().y();
p->v1.x = 0;
p->v1.y = 0;
p->v2.x = m_size.width();
p->v2.y = 0;
p->v3.x = 0;
p->v3.y = m_size.height();
p->v4.x = m_size.width();
p->v4.y = m_size.height();
markDirty(DirtyGeometry);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12SPRITENODE_H
#define QSGD3D12SPRITENODE_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/qsgadaptationlayer_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12SpriteMaterial;
class QSGD3D12SpriteNode : public QSGSpriteNode
{
public:
QSGD3D12SpriteNode();
void setTexture(QSGTexture *texture) override;
void setTime(float time) override;
void setSourceA(const QPoint &source) override;
void setSourceB(const QPoint &source) override;
void setSpriteSize(const QSize &size) override;
void setSheetSize(const QSize &size) override;
void setSize(const QSizeF &size) override;
void setFiltering(QSGTexture::Filtering filtering) override;
void update() override;
private:
void updateGeometry();
QSGD3D12SpriteMaterial *m_material;
QSGGeometry *m_geometry;
bool m_geometryDirty;
QPoint m_sourceA;
QPoint m_sourceB;
QSize m_spriteSize;
QSize m_sheetSize;
QSizeF m_size;
};
QT_END_NAMESPACE
#endif // QSGD3D12SPRITENODE_H

View File

@ -331,10 +331,11 @@ bool QSGD3D12RenderThread::event(QEvent *e)
if (needsWindow) {
// Must only ever get here when there is no window or releaseResources() has been called.
const int samples = wme->window->format().samples();
const bool alpha = wme->window->format().alphaBufferSize() > 0;
if (Q_UNLIKELY(debug_loop()))
qDebug() << "RT - WM_RequestSync - initializing D3D12 engine" << wme->window
<< wme->size << wme->dpr << samples;
engine->attachToWindow(wme->window->winId(), wme->size, wme->dpr, samples);
<< wme->size << wme->dpr << samples << alpha;
engine->attachToWindow(wme->window->winId(), wme->size, wme->dpr, samples, alpha);
}
exposedWindow = wme->window;
engine->setWindowSize(wme->size, wme->dpr);

View File

@ -108,6 +108,16 @@ shadereffectdefault_pshader.header = ps_shadereffectdefault.hlslh
shadereffectdefault_pshader.entry = PS_DefaultShaderEffect
shadereffectdefault_pshader.type = ps_5_0
sprite_VSPS = $$PWD/sprite.hlsl
sprite_vshader.input = sprite_VSPS
sprite_vshader.header = vs_sprite.hlslh
sprite_vshader.entry = VS_Sprite
sprite_vshader.type = vs_5_0
sprite_pshader.input = sprite_VSPS
sprite_pshader.header = ps_sprite.hlslh
sprite_pshader.entry = PS_Sprite
sprite_pshader.type = ps_5_0
tdr_CS = $$PWD/tdr.hlsl
tdr_cshader.input = tdr_CS
tdr_cshader.header = cs_tdr.hlslh
@ -125,6 +135,7 @@ HLSL_SHADERS = \
textmask_vshader textmask_pshader24 textmask_pshader32 textmask_pshader8 \
styledtext_vshader styledtext_pshader outlinedtext_vshader outlinedtext_pshader \
shadereffectdefault_vshader shadereffectdefault_pshader \
sprite_vshader sprite_pshader \
tdr_cshader
load(hlsl_bytecode_header)

View File

@ -0,0 +1,43 @@
struct VSInput
{
float4 position : POSITION;
float2 coord : TEXCOORD0;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
float4 animPos;
float3 animData;
float opacity;
};
struct PSInput
{
float4 position : SV_POSITION;
float4 fTexS : TEXCOORD0;
float progress : TEXCOORD1;
};
Texture2D tex : register(t0);
SamplerState samp : register(s0);
PSInput VS_Sprite(VSInput input)
{
PSInput result;
result.position = mul(mvp, input.position);
result.progress = animData.z;
// Calculate frame location in texture
result.fTexS.xy = animPos.xy + input.coord.xy * animData.xy;
// Next frame is also passed, for interpolation
result.fTexS.zw = animPos.zw + input.coord.xy * animData.xy;
return result;
}
float4 PS_Sprite(PSInput input) : SV_TARGET
{
return lerp(tex.Sample(samp, input.fTexS.xy), tex.Sample(samp, input.fTexS.zw), input.progress) * opacity;
}

View File

@ -193,7 +193,7 @@ void Object::appendFunction(QmlIR::Function *f)
QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == 0);
const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
if (!isListBinding && !bindingToDefaultProperty
&& b->type != QV4::CompiledData::Binding::Type_GroupProperty
&& b->type != QV4::CompiledData::Binding::Type_AttachedProperty
@ -640,7 +640,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
}
if (node->versionToken.isValid()) {
extractVersion(textRefAt(node->versionToken), &import->majorVersion, &import->minorVersion);
int major, minor;
extractVersion(textRefAt(node->versionToken), &major, &minor);
import->majorVersion = major;
import->minorVersion = minor;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false;
@ -997,13 +1000,13 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->value.b = false;
} else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = lit->value;
binding->setNumberValueInternal(lit->value);
} else {
if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = -lit->value;
binding->setNumberValueInternal(-lit->value);
}
}
}

View File

@ -350,7 +350,7 @@ public:
int id;
int indexOfDefaultPropertyOrAlias;
bool defaultPropertyIsAlias;
int flags;
quint32 flags;
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
@ -400,6 +400,8 @@ public:
FixedPoolArray<int> runtimeFunctionIndices;
FixedPoolArray<quint32> namedObjectsInComponent;
int namedObjectsInComponentCount() const { return namedObjectsInComponent.count; }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
private:
friend struct IRLoader;
@ -436,7 +438,6 @@ struct Q_QML_PRIVATE_EXPORT Document
quint32 unitFlags;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit;
QHash<int, QStringList> extraSignalParameters;
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }

View File

@ -507,6 +507,240 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
return noError;
}
template <typename ObjectContainer>
class QQmlPropertyCacheAliasCreator
{
public:
typedef typename ObjectContainer::CompiledObject CompiledObject;
QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
void appendAliasPropertiesToMetaObjects();
void appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
private:
void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
void propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, quint32 *propertyFlags);
void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
int objectForId(const CompiledObject &component, int id) const;
QQmlPropertyCacheVector *propertyCaches;
const ObjectContainer *objectContainer;
};
template <typename ObjectContainer>
inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
: propertyCaches(propertyCaches)
, objectContainer(objectContainer)
{
}
template <typename ObjectContainer>
inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
{
for (int i = 0; i < objectContainer->objectCount(); ++i) {
const CompiledObject &component = *objectContainer->objectAt(i);
if (!(component.flags & QV4::CompiledData::Object::IsComponent))
continue;
const auto rootBinding = component.bindingsBegin();
appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
}
const int rootObjectIndex = objectContainer->rootObjectIndex();
appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
}
template <typename ObjectContainer>
inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
{
QVector<int> objectsWithAliases;
collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
if (objectsWithAliases.isEmpty())
return;
const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias) {
Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
const int targetObjectIndex = objectForId(component, alias->targetObjectId);
Q_ASSERT(targetObjectIndex >= 0);
if (alias->encodedMetaPropertyIndex == -1)
continue;
const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
int coreIndex;
QQmlPropertyData::decodeValueTypePropertyIndex(alias->encodedMetaPropertyIndex, &coreIndex);
QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
if (!targetProperty)
return false;
}
return true;
};
do {
QVector<int> pendingObjects;
for (int objectIndex: qAsConst(objectsWithAliases)) {
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (allAliasTargetsExist(object)) {
appendAliasesToPropertyCache(component, objectIndex);
} else {
pendingObjects.append(objectIndex);
}
}
qSwap(objectsWithAliases, pendingObjects);
} while (!objectsWithAliases.isEmpty());
}
template <typename ObjectContainer>
inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (object.aliasCount() > 0)
objectsWithAliases->append(objectIndex);
// Stop at Component boundary
if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != objectContainer->rootObjectIndex())
return;
for (auto binding = object.bindingsBegin(), end = object.bindingsEnd(); binding != end; ++binding) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
continue;
collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
}
}
template <typename ObjectContainer>
inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, quint32 *propertyFlags)
{
const int targetObjectIndex = objectForId(component, alias.targetObjectId);
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
*type = 0;
bool writable = false;
bool resettable = false;
*propertyFlags = QQmlPropertyData::IsAlias;
if (alias.aliasToLocalAlias) {
auto targetAlias = targetObject.aliasesBegin();
for (uint i = 0; i < alias.localAliasIndex; ++i)
++targetAlias;
propertyDataForAlias(component, *targetAlias, type, propertyFlags);
return;
} else if (alias.encodedMetaPropertyIndex == -1) {
Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
auto *typeRef = objectContainer->resolvedTypes.value(targetObject.inheritedTypeNameIndex);
Q_ASSERT(typeRef);
if (typeRef->type)
*type = typeRef->type->typeId();
else
*type = typeRef->compilationUnit->metaTypeId;
*propertyFlags |= QQmlPropertyData::IsQObjectDerived;
} else {
int coreIndex;
int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(alias.encodedMetaPropertyIndex, &coreIndex);
QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
Q_ASSERT(targetProperty);
*type = targetProperty->propType;
writable = targetProperty->isWritable();
resettable = targetProperty->isResettable();
if (valueTypeIndex != -1) {
const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
*type = QVariant::Int;
else
*type = valueTypeMetaObject->property(valueTypeIndex).userType();
} else {
if (targetProperty->isEnum()) {
*type = QVariant::Int;
} else {
// Copy type flags
*propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
if (targetProperty->isVarProperty())
*propertyFlags |= QQmlPropertyData::IsQVariant;
}
}
}
if (!(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable)
*propertyFlags |= QQmlPropertyData::IsWritable;
else
*propertyFlags &= ~QQmlPropertyData::IsWritable;
if (resettable)
*propertyFlags |= QQmlPropertyData::IsResettable;
else
*propertyFlags &= ~QQmlPropertyData::IsResettable;
}
template <typename ObjectContainer>
inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex)
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (!object.aliasCount())
return;
QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
Q_ASSERT(propertyCache);
int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
int aliasIndex = 0;
for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias, ++aliasIndex) {
Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
int type = 0;
quint32 propertyFlags = 0;
propertyDataForAlias(component, *alias, &type, &propertyFlags);
const QString propertyName = objectContainer->stringAt(alias->nameIndex);
if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
type, effectiveSignalIndex++);
}
}
template <typename ObjectContainer>
inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
{
for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
const int candidateIndex = component.namedObjectsInComponentTable()[i];
const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
if (candidate.id == id)
return candidateIndex;
}
return -1;
}
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHECREATOR_P_H

View File

@ -271,6 +271,28 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip
return object->bindingAsString(document, scriptIndex);
}
void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
{
const quint32 moduleIdx = registerString(module);
const quint32 qualifierIdx = registerString(qualifier);
for (int i = 0, count = document->imports.count(); i < count; ++i) {
const QV4::CompiledData::Import *existingImport = document->imports.at(i);
if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
&& existingImport->uriIndex == moduleIdx
&& existingImport->qualifierIndex == qualifierIdx)
return;
}
auto pool = memoryPool();
QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
import->type = QV4::CompiledData::Import::ImportLibrary;
import->majorVersion = majorVersion;
import->minorVersion = minorVersion;
import->uriIndex = moduleIdx;
import->qualifierIndex = qualifierIdx;
document->imports.append(import);
}
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
: compiler(typeCompiler)
{
@ -546,7 +568,7 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
}
binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = (double)enumValue;
binding->setNumberValueInternal((double)enumValue);
binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
return true;
}
@ -701,7 +723,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
if (!binding->isValueBinding())
continue;
bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
}
@ -733,7 +755,7 @@ void QQmlScriptStringScanner::scan()
if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (!pd || pd->propType != scriptStringMetaType)
continue;
@ -753,7 +775,6 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
, pool(typeCompiler->memoryPool())
, qmlObjects(typeCompiler->qmlObjects())
, indexOfRootObject(typeCompiler->rootObjectIndex())
, _componentIndex(-1)
, resolvedTypes(&typeCompiler->resolvedTypes)
, propertyCaches(std::move(typeCompiler->takePropertyCaches()))
{
@ -783,7 +804,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
}
QQmlPropertyData *pd = 0;
if (binding->propertyNameIndex != 0) {
if (binding->propertyNameIndex != quint32(0)) {
bool notInRevision = false;
pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
} else {
@ -803,11 +824,15 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
if (!mo)
continue;
// emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
Q_ASSERT(componentType);
const QString qualifier = QStringLiteral("QmlInternals");
compiler->addImport(componentType->module(), qualifier, componentType->majorVersion(), componentType->minorVersion());
QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType->elementName()), compiler->registerString(QString()));
syntheticComponent->location = binding->valueLocation;
syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
@ -898,7 +923,6 @@ bool QQmlComponentAndAliasResolver::resolve()
QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
const QmlIR::Binding *rootBinding = component->firstBinding();
_componentIndex = i;
_idToObjectIndex.clear();
_objectsWithAliases.clear();
@ -906,24 +930,24 @@ bool QQmlComponentAndAliasResolver::resolve()
if (!collectIdsAndAliases(rootBinding->value.objectIndex))
return false;
if (!resolveAliases())
return false;
component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
if (!resolveAliases(componentRoots.at(i)))
return false;
}
// Collect ids and aliases for root
_componentIndex = -1;
_idToObjectIndex.clear();
_objectsWithAliases.clear();
collectIdsAndAliases(indexOfRootObject);
resolveAliases();
QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
if (!resolveAliases(indexOfRootObject))
return false;
// Implicit component insertion may have added objects and thus we also need
// to extend the symmetric propertyCaches.
compiler->setPropertyCaches(std::move(propertyCaches));
@ -965,139 +989,169 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
return true;
}
bool QQmlComponentAndAliasResolver::resolveAliases()
bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
{
foreach (int objectIndex, _objectsWithAliases) {
const QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (_objectsWithAliases.isEmpty())
return true;
QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
Q_ASSERT(propertyCache);
QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
bool atLeastOneAliasResolved;
do {
atLeastOneAliasResolved = false;
QVector<int> pendingObjects;
int aliasIndex = 0;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
const int idIndex = alias->idIndex;
const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
if (targetObjectIndex == -1) {
recordError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
for (int objectIndex: qAsConst(_objectsWithAliases)) {
QQmlCompileError error;
const auto result = resolveAliasesInObject(objectIndex, &error);
if (error.isSet()) {
recordError(error);
return false;
}
Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved));
alias->flags |= QV4::CompiledData::Alias::Resolved;
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
alias->targetObjectId = targetObject->id;
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
QStringRef property;
QStringRef subProperty;
const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
if (propertySeparator != -1) {
property = aliasPropertyValue.leftRef(propertySeparator);
subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
} else
property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
int propIdx = -1;
int type = 0;
bool writable = false;
bool resettable = false;
quint32 propertyFlags = QQmlPropertyData::IsAlias;
if (property.isEmpty()) {
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
auto *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
if (typeRef->type)
type = typeRef->type->typeId();
else
type = typeRef->compilationUnit->metaTypeId;
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
propertyFlags |= QQmlPropertyData::IsQObjectDerived;
if (result == AllAliasesResolved) {
aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
atLeastOneAliasResolved = true;
} else if (result == SomeAliasesResolved) {
atLeastOneAliasResolved = true;
pendingObjects.append(objectIndex);
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
Q_ASSERT(targetCache);
QmlIR::PropertyResolver resolver(targetCache);
pendingObjects.append(objectIndex);
}
}
qSwap(_objectsWithAliases, pendingObjects);
} while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
QQmlPropertyData *targetProperty = resolver.property(property.toString());
if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
return false;
if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
recordError(alias->location, tr("Circular alias reference detected"));
return false;
}
}
}
return true;
}
QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
{
const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
if (!obj->aliasCount())
return AllAliasesResolved;
int numResolvedAliases = 0;
bool seenUnresolvedAlias = false;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
if (alias->flags & QV4::CompiledData::Alias::Resolved)
continue;
seenUnresolvedAlias = true;
const int idIndex = alias->idIndex;
const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
if (targetObjectIndex == -1) {
*error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
break;
}
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
alias->targetObjectId = targetObject->id;
alias->aliasToLocalAlias = false;
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
QStringRef property;
QStringRef subProperty;
const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
if (propertySeparator != -1) {
property = aliasPropertyValue.leftRef(propertySeparator);
subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
} else
property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
int propIdx = -1;
if (property.isEmpty()) {
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
Q_ASSERT(targetCache);
QmlIR::PropertyResolver resolver(targetCache);
QQmlPropertyData *targetProperty = resolver.property(property.toString());
// If it's an alias that we haven't resolved yet, try again later.
if (!targetProperty) {
bool aliasPointsToOtherAlias = false;
int localAliasIndex = 0;
for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
if (stringAt(targetAlias->nameIndex) == property) {
aliasPointsToOtherAlias = true;
break;
}
}
propIdx = targetProperty->coreIndex;
type = targetProperty->propType;
writable = targetProperty->isWritable();
resettable = targetProperty->isResettable();
if (!subProperty.isEmpty()) {
const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type);
if (!valueTypeMetaObject) {
recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
return false;
if (aliasPointsToOtherAlias) {
if (targetObjectIndex == objectIndex) {
alias->localAliasIndex = localAliasIndex;
alias->aliasToLocalAlias = true;
alias->flags |= QV4::CompiledData::Alias::Resolved;
++numResolvedAliases;
continue;
}
int valueTypeIndex =
valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
if (valueTypeIndex == -1) {
recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
return false;
}
Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
propIdx = QQmlPropertyData::encodeValueTypePropertyIndex(propIdx, valueTypeIndex);
if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
type = QVariant::Int;
else
type = valueTypeMetaObject->property(valueTypeIndex).userType();
} else {
if (targetProperty->isEnum()) {
type = QVariant::Int;
} else {
// Copy type flags
propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
if (targetProperty->isVarProperty())
propertyFlags |= QQmlPropertyData::IsQVariant;
if (targetProperty->isQObject())
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
}
// Try again later and resolve the target alias first.
_objectsWithAliases.append(objectIndex);
// restore
alias->idIndex = idIndex;
break;
}
}
alias->encodedMetaPropertyIndex = propIdx;
if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
*error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
if (!(alias->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
propertyFlags |= QQmlPropertyData::IsWritable;
else
propertyFlags &= ~QQmlPropertyData::IsWritable;
propIdx = targetProperty->coreIndex;
if (resettable)
propertyFlags |= QQmlPropertyData::IsResettable;
else
propertyFlags &= ~QQmlPropertyData::IsResettable;
if (!subProperty.isEmpty()) {
const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType);
if (!valueTypeMetaObject) {
*error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
break;
}
QString propertyName = stringAt(alias->nameIndex);
if (obj->defaultPropertyIsAlias && aliasIndex == obj->indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
type, effectiveSignalIndex++);
int valueTypeIndex =
valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
if (valueTypeIndex == -1) {
*error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
break;
}
Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
propIdx = QQmlPropertyData::encodeValueTypePropertyIndex(propIdx, valueTypeIndex);
} else {
if (targetProperty->isQObject())
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
}
}
alias->encodedMetaPropertyIndex = propIdx;
alias->flags |= QV4::CompiledData::Alias::Resolved;
numResolvedAliases++;
}
return true;
if (numResolvedAliases == 0)
return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved;
return SomeAliasesResolved;
}
QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
@ -1346,7 +1400,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
QmlIR::Binding *previousBinding = 0;
QmlIR::Binding *binding = object->firstBinding();
while (binding) {
if (binding->propertyNameIndex == 0 || stringAt(binding->propertyNameIndex) != defaultProperty) {
if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
previousBinding = binding;
binding = binding->next;
continue;

View File

@ -133,6 +133,8 @@ public:
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
@ -263,7 +265,16 @@ public:
protected:
void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
bool collectIdsAndAliases(int objectIndex);
bool resolveAliases();
bool resolveAliases(int componentIndex);
void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
enum AliasResolutionResult {
NoAliasResolved,
SomeAliasesResolved,
AllAliasesResolved
};
AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error);
QQmlEnginePrivate *enginePrivate;
QQmlJS::MemoryPool *pool;
@ -274,9 +285,8 @@ protected:
// indices of the objects that are actually Component {}
QVector<quint32> componentRoots;
int _componentIndex;
QHash<int, int> _idToObjectIndex;
QList<int> _objectsWithAliases;
QVector<int> _objectsWithAliases;
QHash<int, QV4::CompiledData::CompilationUnit::ResolvedTypeReference*> *resolvedTypes;
QQmlPropertyCacheVector propertyCaches;

View File

@ -122,7 +122,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i;
Lookup::Type type = Lookup::Type(compiledLookups[i].type_and_flags);
Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@ -215,8 +215,8 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
void CompilationUnit::destroy()
{
QQmlEngine *qmlEngine = 0;
if (engine)
qmlEngine = engine->qmlEngine();
if (engine && engine->v8Engine)
qmlEngine = engine->v8Engine->engine();
if (qmlEngine)
QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this);
else
@ -229,7 +229,7 @@ IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjec
if (it == namedObjectsPerComponentCache.end()) {
IdentifierHash<int> namedObjectCache(engine);
const CompiledData::Object *component = data->objectAt(componentObjectIndex);
const quint32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
const LEUInt32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
@ -355,7 +355,7 @@ QString Binding::valueAsString(const Unit *unit) const
case Type_Boolean:
return value.b ? QStringLiteral("true") : QStringLiteral("false");
case Type_Number:
return QString::number(value.d);
return QString::number(valueAsNumber());
case Type_Invalid:
return QString();
#ifdef QT_NO_TRANSLATION

View File

@ -62,6 +62,7 @@
#include <private/qqmlnullablevalue_p.h>
#include <private/qv4identifier_p.h>
#include <private/qflagpointer_p.h>
#include <private/qjson_p.h>
#ifndef V4_BOOTSTRAP
#include <private/qqmltypenamecache_p.h>
#include <private/qqmlpropertycache_p.h>
@ -90,6 +91,12 @@ struct Function;
namespace CompiledData {
typedef QJsonPrivate::q_littleendian<qint16> LEInt16;
typedef QJsonPrivate::q_littleendian<quint16> LEUInt16;
typedef QJsonPrivate::q_littleendian<quint32> LEUInt32;
typedef QJsonPrivate::q_littleendian<qint32> LEInt32;
typedef QJsonPrivate::q_littleendian<quint64> LEUInt64;
struct String;
struct Function;
struct Lookup;
@ -115,10 +122,12 @@ struct TableIterator
struct Location
{
qint32 line : 20;
qint32 column : 12;
union {
QJsonPrivate::qle_bitfield<0, 20> line;
QJsonPrivate::qle_bitfield<20, 12> column;
};
Location(): line(-1), column(-1) {}
Location() { line = 0; column = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
@ -128,20 +137,20 @@ struct Location
struct RegExp
{
enum Flags {
enum Flags : unsigned int {
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04
};
quint32 flags : 4;
quint32 stringIndex : 28;
static int calculateSize() { return sizeof(RegExp); }
union {
QJsonPrivate::qle_bitfield<0, 4> flags;
QJsonPrivate::qle_bitfield<4, 28> stringIndex;
};
};
struct Lookup
{
enum Type {
enum Type : unsigned int {
Type_Getter = 0x0,
Type_Setter = 0x1,
Type_GlobalGetter = 2,
@ -149,21 +158,27 @@ struct Lookup
Type_IndexedSetter = 4
};
quint32 type_and_flags : 4;
quint32 nameIndex : 28;
union {
QJsonPrivate::qle_bitfield<0, 4> type_and_flags;
QJsonPrivate::qle_bitfield<4, 28> nameIndex;
};
static int calculateSize() { return sizeof(Lookup); }
Lookup() { type_and_flags = 0; nameIndex = 0; }
};
struct JSClassMember
{
quint32 nameOffset : 31;
quint32 isAccessor : 1;
union {
QJsonPrivate::qle_bitfield<0, 31> nameOffset;
QJsonPrivate::qle_bitfield<31, 1> isAccessor;
};
JSClassMember() { nameOffset = 0; isAccessor = 0; }
};
struct JSClass
{
uint nMembers;
LEUInt32 nMembers;
// JSClassMember[nMembers]
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
@ -171,7 +186,7 @@ struct JSClass
struct String
{
qint32 size;
LEInt32 size;
// uint16 strdata[]
static int calculateSize(const QString &str) {
@ -181,7 +196,7 @@ struct String
struct Function
{
enum Flags {
enum Flags : unsigned int {
HasDirectEval = 0x1,
UsesArgumentsObject = 0x2,
IsStrict = 0x4,
@ -189,44 +204,45 @@ struct Function
HasCatchOrWith = 0x10
};
quint8 flags;
quint32 nameIndex;
quint32 nFormals;
quint32 formalsOffset;
quint32 nLocals;
quint32 localsOffset;
quint32 nInnerFunctions;
quint32 innerFunctionsOffset;
LEUInt32 nameIndex;
LEUInt32 nFormals;
LEUInt32 formalsOffset;
LEUInt32 nLocals;
LEUInt32 localsOffset;
LEUInt32 nInnerFunctions;
Location location;
// Qml Extensions Begin
quint32 nDependingIdObjects;
quint32 dependingIdObjectsOffset; // Array of resolved ID objects
quint32 nDependingContextProperties;
quint32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
quint32 nDependingScopeProperties;
quint32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
LEUInt32 nDependingIdObjects;
LEUInt32 dependingIdObjectsOffset; // Array of resolved ID objects
LEUInt32 nDependingContextProperties;
LEUInt32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
LEUInt32 nDependingScopeProperties;
LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
// Qml Extensions End
// Absolute offset into file where the code for this function is located. Only used when the function
// is serialized.
quint64 codeOffset;
quint64 codeSize;
LEUInt64 codeOffset;
LEUInt64 codeSize;
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
// quint32 offsetForInnerFunctions[nInnerFunctions]
// Function[nInnerFunctions]
const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
const quint32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
const quint32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
const quint32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
// Keep all unaligned data at the end
quint8 flags;
const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
const LEUInt32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
const LEUInt32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
const LEUInt32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
// --- QQmlPropertyCacheCreator interface
const quint32 *formalsBegin() const { return formalsTable(); }
const quint32 *formalsEnd() const { return formalsTable() + nFormals; }
const LEUInt32 *formalsBegin() const { return formalsTable(); }
const LEUInt32 *formalsEnd() const { return formalsTable() + nFormals; }
// ---
inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
@ -239,15 +255,15 @@ struct Function
// Qml data structures
struct Q_QML_EXPORT TranslationData {
quint32 commentIndex;
int number;
LEUInt32 commentIndex;
LEInt32 number;
};
struct Q_QML_PRIVATE_EXPORT Binding
{
quint32 propertyNameIndex;
LEUInt32 propertyNameIndex;
enum ValueType {
enum ValueType : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
@ -260,7 +276,7 @@ struct Q_QML_PRIVATE_EXPORT Binding
Type_GroupProperty
};
enum Flags {
enum Flags : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
@ -272,16 +288,18 @@ struct Q_QML_PRIVATE_EXPORT Binding
IsCustomParserBinding = 0x100,
};
quint32 flags : 16;
quint32 type : 16;
union {
QJsonPrivate::qle_bitfield<0, 16> flags;
QJsonPrivate::qle_bitfield<16, 16> type;
};
union {
bool b;
double d;
quint32 compiledScriptIndex; // used when Type_Script
quint32 objectIndex;
quint64 doubleValue; // do not access directly, needs endian protected access
LEUInt32 compiledScriptIndex; // used when Type_Script
LEUInt32 objectIndex;
TranslationData translationData; // used when Type_Translation
} value;
quint32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
LEUInt32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
Location location;
Location valueLocation;
@ -341,11 +359,20 @@ struct Q_QML_PRIVATE_EXPORT Binding
QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const
{
if (type == Type_Number)
return value.d;
return 0.0;
if (type != Type_Number)
return 0.0;
quint64 intval = qFromLittleEndian<quint64>(value.doubleValue);
double d;
memcpy(&d, &intval, sizeof(double));
return d;
}
void setNumberValueInternal(double d)
{
quint64 intval;
memcpy(&intval, &d, sizeof(double));
value.doubleValue = qToLittleEndian<quint64>(intval);
}
bool valueAsBoolean() const
{
if (type == Type_Boolean)
@ -357,16 +384,16 @@ struct Q_QML_PRIVATE_EXPORT Binding
struct Parameter
{
quint32 nameIndex;
quint32 type;
quint32 customTypeNameIndex;
LEUInt32 nameIndex;
LEUInt32 type;
LEUInt32 customTypeNameIndex;
Location location;
};
struct Signal
{
quint32 nameIndex;
quint32 nParameters;
LEUInt32 nameIndex;
LEUInt32 nParameters;
Location location;
// Parameter parameters[1];
@ -389,37 +416,43 @@ struct Signal
struct Property
{
enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
Font, Time, Date, DateTime, Rect, Point, Size,
Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
Custom, CustomList };
enum Flags {
enum Flags : unsigned int {
IsReadOnly = 0x1
};
quint32 nameIndex;
quint32 type : 31;
quint32 flags : 1; // readonly
quint32 customTypeNameIndex; // If type >= Custom
LEUInt32 nameIndex;
union {
QJsonPrivate::qle_bitfield<0, 31> type;
QJsonPrivate::qle_bitfield<31, 1> flags; // readonly
};
LEUInt32 customTypeNameIndex; // If type >= Custom
Location location;
};
struct Alias {
enum Flags {
enum Flags : unsigned int {
IsReadOnly = 0x1,
Resolved = 0x2,
AliasPointsToPointerObject = 0x4
};
quint32 nameIndex : 29;
quint32 flags : 3;
union {
quint32 idIndex; // string index
quint32 targetObjectId; // object id index (in QQmlContextData::idValues)
QJsonPrivate::qle_bitfield<0, 29> nameIndex;
QJsonPrivate::qle_bitfield<29, 3> flags;
};
union {
quint32 propertyNameIndex; // string index
qint32 encodedMetaPropertyIndex;
LEUInt32 idIndex; // string index
QJsonPrivate::qle_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
QJsonPrivate::qle_bitfield<31, 1> aliasToLocalAlias;
};
union {
LEUInt32 propertyNameIndex; // string index
LEInt32 encodedMetaPropertyIndex;
LEUInt32 localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
};
Location location;
Location referenceLocation;
@ -432,7 +465,7 @@ struct Alias {
struct Object
{
enum Flags {
enum Flags : unsigned int {
NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred
@ -442,24 +475,26 @@ struct Object
// Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
quint32 inheritedTypeNameIndex;
quint32 idNameIndex;
qint32 id : 16;
qint32 flags : 15;
quint32 defaultPropertyIsAlias : 1;
qint32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint32 nFunctions;
quint32 offsetToFunctions;
quint32 nProperties;
quint32 offsetToProperties;
quint32 nAliases;
quint32 offsetToAliases;
quint32 nSignals;
quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
quint32 nBindings;
quint32 offsetToBindings;
quint32 nNamedObjectsInComponent;
quint32 offsetToNamedObjectsInComponent;
LEUInt32 inheritedTypeNameIndex;
LEUInt32 idNameIndex;
union {
QJsonPrivate::qle_bitfield<0, 15> flags;
QJsonPrivate::qle_bitfield<15, 1> defaultPropertyIsAlias;
QJsonPrivate::qle_signedbitfield<16, 16> id;
};
LEInt32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
LEUInt32 nFunctions;
LEUInt32 offsetToFunctions;
LEUInt32 nProperties;
LEUInt32 offsetToProperties;
LEUInt32 nAliases;
LEUInt32 offsetToAliases;
LEUInt32 nSignals;
LEUInt32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
LEUInt32 nBindings;
LEUInt32 offsetToBindings;
LEUInt32 nNamedObjectsInComponent;
LEUInt32 offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
// Function[]
@ -480,9 +515,9 @@ struct Object
) & ~0x7;
}
const quint32 *functionOffsetTable() const
const LEUInt32 *functionOffsetTable() const
{
return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
}
const Property *propertyTable() const
@ -502,14 +537,14 @@ struct Object
const Signal *signalAt(int idx) const
{
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
const uint offset = offsetTable[idx];
const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
}
const quint32 *namedObjectsInComponentTable() const
const LEUInt32 *namedObjectsInComponentTable() const
{
return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
}
// --- QQmlPropertyCacheCreator interface
@ -530,27 +565,29 @@ struct Object
typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
// ---
};
struct Import
{
enum ImportType {
enum ImportType : unsigned int {
ImportLibrary = 0x1,
ImportFile = 0x2,
ImportScript = 0x3
};
quint32 type;
quint8 type;
quint32 uriIndex;
quint32 qualifierIndex;
LEUInt32 uriIndex;
LEUInt32 qualifierIndex;
qint32 majorVersion;
qint32 minorVersion;
LEInt32 majorVersion;
LEInt32 minorVersion;
Location location;
Import(): type(0), uriIndex(0), qualifierIndex(0), majorVersion(0), minorVersion(0) {}
Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
};
static const char magic_str[] = "qv4cdata";
@ -558,47 +595,47 @@ static const char magic_str[] = "qv4cdata";
struct Unit
{
char magic[8];
qint16 architecture;
qint16 version;
quint32 unitSize; // Size of the Unit and any depending data.
LEInt16 architecture;
LEInt16 version;
LEUInt32 unitSize; // Size of the Unit and any depending data.
enum {
enum : unsigned int {
IsJavascript = 0x1,
IsQml = 0x2,
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
IsSharedLibrary = 0x10 // .pragma shared?
};
quint32 flags;
uint stringTableSize;
uint offsetToStringTable;
uint functionTableSize;
uint offsetToFunctionTable;
uint lookupTableSize;
uint offsetToLookupTable;
uint regexpTableSize;
uint offsetToRegexpTable;
uint constantTableSize;
uint offsetToConstantTable;
uint jsClassTableSize;
uint offsetToJSClassTable;
qint32 indexOfRootFunction;
quint32 sourceFileIndex;
LEUInt32 flags;
LEUInt32 stringTableSize;
LEUInt32 offsetToStringTable;
LEUInt32 functionTableSize;
LEUInt32 offsetToFunctionTable;
LEUInt32 lookupTableSize;
LEUInt32 offsetToLookupTable;
LEUInt32 regexpTableSize;
LEUInt32 offsetToRegexpTable;
LEUInt32 constantTableSize;
LEUInt32 offsetToConstantTable;
LEUInt32 jsClassTableSize;
LEUInt32 offsetToJSClassTable;
LEInt32 indexOfRootFunction;
LEUInt32 sourceFileIndex;
/* QML specific fields */
quint32 nImports;
quint32 offsetToImports;
quint32 nObjects;
quint32 offsetToObjects;
quint32 indexOfRootObject;
LEUInt32 nImports;
LEUInt32 offsetToImports;
LEUInt32 nObjects;
LEUInt32 offsetToObjects;
LEUInt32 indexOfRootObject;
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
const Object *objectAt(int idx) const {
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
const uint offset = offsetTable[idx];
const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
}
@ -608,22 +645,31 @@ struct Unit
/* end QML specific fields*/
QString stringAt(int idx) const {
const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
const uint offset = offsetTable[idx];
const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
const LEUInt32 offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
if (str->size == 0)
return QString();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
if (flags & StaticData)
return QString::fromRawData(characters, str->size);
return QString(characters, str->size);
#else
const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1);
QString qstr(str->size, Qt::Uninitialized);
QChar *ch = qstr.data();
for (int i = 0; i < str->size; ++i)
ch[i] = QChar(characters[i]);
return qstr;
#endif
}
const uint *functionOffsetTable() const { return reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
const LEUInt32 *functionOffsetTable() const { return reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
const Function *functionAt(int idx) const {
const uint *offsetTable = functionOffsetTable();
const uint offset = offsetTable[idx];
const LEUInt32 *offsetTable = functionOffsetTable();
const LEUInt32 offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
@ -636,22 +682,13 @@ struct Unit
}
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
const uint offset = offsetTable[idx];
const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
const LEUInt32 offset = offsetTable[idx];
const char *ptr = reinterpret_cast<const char *>(this) + offset;
const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
*nMembers = klass->nMembers;
return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
}
static int calculateSize(uint nFunctions, uint nRegExps, uint nConstants,
uint nLookups, uint nClasses) {
return (sizeof(Unit)
+ (nFunctions + nClasses) * sizeof(uint)
+ nRegExps * RegExp::calculateSize()
+ nConstants * sizeof(QV4::ReturnedValue)
+ nLookups * Lookup::calculateSize()
+ 7) & ~7; }
};
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)

View File

@ -42,6 +42,7 @@
#include <qv4isel_p.h>
#include <private/qv4string_p.h>
#include <private/qv4value_p.h>
#include <private/qv4alloca_p.h>
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
@ -75,15 +76,21 @@ void QV4::Compiler::StringTableGenerator::clear()
void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
uint *stringTable = reinterpret_cast<uint *>(dataStart + unit->offsetToStringTable);
CompiledData::LEUInt32 *stringTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataStart + unit->offsetToStringTable);
char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
for (int i = 0; i < strings.size(); ++i) {
stringTable[i] = stringData - dataStart;
const QString &qstr = strings.at(i);
QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData);
QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
s->size = qstr.length();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort));
#else
ushort *uc = reinterpret_cast<ushort *>(s + 1);
for (int i = 0; i < qstr.length(); ++i)
uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
#endif
stringData += QV4::CompiledData::String::calculateSize(qstr);
}
@ -91,7 +98,6 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module)
: irModule(module)
, jsClassDataSize(0)
{
// Make sure the empty string always gets index 0
registerString(QString());
@ -173,30 +179,32 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
{
// ### re-use existing class definitions.
QList<CompiledData::JSClassMember> members;
members.reserve(count);
const int size = CompiledData::JSClass::calculateSize(count);
jsClassOffsets.append(jsClassData.size());
const int oldSize = jsClassData.size();
jsClassData.resize(jsClassData.size() + size);
memset(jsClassData.data() + oldSize, 0, size);
CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
jsClass->nMembers = count;
CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
IR::ExprList *it = args;
for (int i = 0; i < count; ++i, it = it->next) {
CompiledData::JSClassMember member;
for (int i = 0; i < count; ++i, it = it->next, ++member) {
QV4::IR::Name *name = it->expr->asName();
it = it->next;
const bool isData = it->expr->asConst()->value;
it = it->next;
member.nameOffset = registerString(*name->id);
member.isAccessor = !isData;
members << member;
member->nameOffset = registerString(*name->id);
member->isAccessor = !isData;
if (!isData)
it = it->next;
}
jsClasses << members;
jsClassDataSize += CompiledData::JSClass::calculateSize(members.count());
return jsClasses.size() - 1;
return jsClassOffsets.size() - 1;
}
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
@ -210,94 +218,45 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(*f->locals.at(i));
}
int unitSize = QV4::CompiledData::Unit::calculateSize(irModule->functions.size(), regexps.size(),
constants.size(), lookups.size(), jsClasses.count());
CompiledData::LEUInt32 *functionOffsets = reinterpret_cast<CompiledData::LEUInt32*>(alloca(irModule->functions.size() * sizeof(CompiledData::LEUInt32)));
uint jsClassDataOffset = 0;
uint functionDataSize = 0;
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *f = irModule->functions.at(i);
functionOffsets.insert(f, functionDataSize + unitSize);
const int qmlIdDepsCount = f->idObjectDependencies.count();
const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
char *dataPtr;
CompiledData::Unit *unit;
{
QV4::CompiledData::Unit tempHeader = generateHeader(option, functionOffsets, &jsClassDataOffset);
dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize));
memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*));
memcpy(unit, &tempHeader, sizeof(tempHeader));
}
const int totalSize = unitSize + functionDataSize + jsClassDataSize + (option == GenerateWithStringTable ? stringTable.sizeOfTableAndData() : 0);
char *data = (char *)malloc(totalSize);
memset(data, 0, totalSize);
QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(CompiledData::LEUInt32));
memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic));
unit->architecture = 0; // ###
unit->flags = QV4::CompiledData::Unit::IsJavascript;
unit->version = 1;
unit->unitSize = totalSize;
unit->functionTableSize = irModule->functions.size();
unit->offsetToFunctionTable = sizeof(*unit);
unit->lookupTableSize = lookups.count();
unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
unit->regexpTableSize = regexps.size();
unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
unit->constantTableSize = constants.size();
unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
unit->jsClassTableSize = jsClasses.count();
unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
if (option == GenerateWithStringTable) {
unit->stringTableSize = stringTable.stringCount();
unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
} else {
unit->stringTableSize = 0;
unit->offsetToStringTable = 0;
}
unit->indexOfRootFunction = -1;
unit->sourceFileIndex = getStringId(irModule->fileName);
unit->nImports = 0;
unit->offsetToImports = 0;
unit->nObjects = 0;
unit->offsetToObjects = 0;
unit->indexOfRootObject = 0;
uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
for (int i = 0; i < irModule->functions.size(); ++i)
functionTable[i] = functionOffsets.value(irModule->functions.at(i));
char *f = data + unitSize;
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *function = irModule->functions.at(i);
if (function == irModule->rootFunction)
unit->indexOfRootFunction = i;
const int bytes = writeFunction(f, function);
f += bytes;
writeFunction(dataPtr + functionOffsets[i], function);
}
CompiledData::Lookup *lookupsToWrite = (CompiledData::Lookup*)(data + unit->offsetToLookupTable);
CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
foreach (const CompiledData::Lookup &l, lookups)
*lookupsToWrite++ = l;
CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable);
CompiledData::RegExp *regexpTable = reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
ReturnedValue *constantTable = (ReturnedValue *)(data + unit->offsetToConstantTable);
ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
// write js classes and js class lookup table
uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
char *jsClass = data + unitSize + functionDataSize;
for (int i = 0; i < jsClasses.count(); ++i) {
jsClassTable[i] = jsClass - data;
{
memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
const QList<CompiledData::JSClassMember> members = jsClasses.at(i);
CompiledData::JSClass *c = reinterpret_cast<CompiledData::JSClass*>(jsClass);
c->nMembers = members.count();
CompiledData::JSClassMember *memberToWrite = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + sizeof(CompiledData::JSClass));
foreach (const CompiledData::JSClassMember &member, members)
*memberToWrite++ = member;
jsClass += CompiledData::JSClass::calculateSize(members.count());
// write js classes and js class lookup table
CompiledData::LEUInt32 *jsClassOffsetTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataPtr + unit->offsetToJSClassTable);
for (int i = 0; i < jsClassOffsets.count(); ++i)
jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
}
// write strings and string table
@ -307,7 +266,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
return unit;
}
int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *irFunction)
void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *irFunction) const
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
@ -334,8 +293,6 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *ir
currentOffset += function->nLocals * sizeof(quint32);
function->nInnerFunctions = irFunction->nestedFunctions.size();
function->innerFunctionsOffset = currentOffset;
currentOffset += function->nInnerFunctions * sizeof(quint32);
function->nDependingIdObjects = 0;
function->nDependingContextProperties = 0;
@ -375,11 +332,6 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *ir
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(*irFunction->locals.at(i));
// write inner functions
quint32 *innerFunctions = (quint32 *)(f + function->innerFunctionsOffset);
for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
for (int id : irFunction->idObjectDependencies) {
@ -398,7 +350,67 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *ir
*writtenDeps++ = property.key(); // property index
*writtenDeps++ = property.value(); // notify index
}
return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions,
function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
}
QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset) const
{
CompiledData::Unit unit;
memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic));
unit.architecture = 0; // ###
unit.flags = QV4::CompiledData::Unit::IsJavascript;
unit.version = 1;
unit.functionTableSize = irModule->functions.size();
quint32 nextOffset = sizeof(CompiledData::Unit);
unit.offsetToFunctionTable = nextOffset;
nextOffset += unit.functionTableSize * sizeof(uint);
unit.lookupTableSize = lookups.count();
unit.offsetToLookupTable = nextOffset;
nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
unit.regexpTableSize = regexps.size();
unit.offsetToRegexpTable = nextOffset;
nextOffset += unit.regexpTableSize * sizeof(CompiledData::RegExp);
unit.constantTableSize = constants.size();
unit.offsetToConstantTable = nextOffset;
nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
unit.jsClassTableSize = jsClassOffsets.count();
unit.offsetToJSClassTable = nextOffset;
nextOffset += unit.jsClassTableSize * sizeof(uint);
*jsClassDataOffset = nextOffset;
nextOffset += jsClassData.size();
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *f = irModule->functions.at(i);
functionOffsets[i] = nextOffset;
const int qmlIdDepsCount = f->idObjectDependencies.count();
const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
nextOffset += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
}
if (option == GenerateWithStringTable) {
unit.stringTableSize = stringTable.stringCount();
unit.offsetToStringTable = nextOffset;
nextOffset += stringTable.sizeOfTableAndData();
} else {
unit.stringTableSize = 0;
unit.offsetToStringTable = 0;
}
unit.indexOfRootFunction = -1;
unit.sourceFileIndex = getStringId(irModule->fileName);
unit.nImports = 0;
unit.offsetToImports = 0;
unit.nObjects = 0;
unit.offsetToObjects = 0;
unit.indexOfRootObject = 0;
unit.unitSize = nextOffset;
return unit;
}

View File

@ -52,6 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4jsir_p.h"
#include <private/qjson_p.h>
QT_BEGIN_NAMESPACE
@ -114,18 +115,19 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable);
// Returns bytes written
int writeFunction(char *f, IR::Function *irFunction);
void writeFunction(char *f, IR::Function *irFunction) const;
StringTableGenerator stringTable;
private:
CompiledData::Unit generateHeader(GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset) const;
IR::Module *irModule;
QHash<IR::Function *, uint> functionOffsets;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
QVector<ReturnedValue> constants;
QList<QList<CompiledData::JSClassMember> > jsClasses;
uint jsClassDataSize;
QByteArray jsClassData;
QVector<int> jsClassOffsets;
};
}

View File

@ -81,19 +81,9 @@ QT_BEGIN_NAMESPACE
F(SetLookup, setLookup) \
F(StoreQObjectProperty, storeQObjectProperty) \
F(LoadQObjectProperty, loadQObjectProperty) \
F(LoadQRealQObjectPropertyDirectly, loadQRealQObjectPropertyDirectly) \
F(LoadQObjectQObjectPropertyDirectly, loadQObjectQObjectPropertyDirectly) \
F(LoadIntQObjectPropertyDirectly, loadIntQObjectPropertyDirectly) \
F(LoadBoolQObjectPropertyDirectly, loadBoolQObjectPropertyDirectly) \
F(LoadQStringQObjectPropertyDirectly, loadQStringQObjectPropertyDirectly) \
F(StoreScopeObjectProperty, storeScopeObjectProperty) \
F(StoreContextObjectProperty, storeContextObjectProperty) \
F(LoadScopeObjectProperty, loadScopeObjectProperty) \
F(LoadScopeObjectQRealPropertyDirectly, loadScopeObjectQRealPropertyDirectly) \
F(LoadScopeObjectQObjectPropertyDirectly, loadScopeObjectQObjectPropertyDirectly) \
F(LoadScopeObjectIntPropertyDirectly, loadScopeObjectIntPropertyDirectly) \
F(LoadScopeObjectBoolPropertyDirectly, loadScopeObjectBoolPropertyDirectly) \
F(LoadScopeObjectQStringPropertyDirectly, loadScopeObjectQStringPropertyDirectly) \
F(LoadContextObjectProperty, loadContextObjectProperty) \
F(LoadIdObject, loadIdObject) \
F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \
@ -333,36 +323,6 @@ union Instr
Param base;
Param result;
};
struct instr_loadScopeObjectQRealPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
};
struct instr_loadScopeObjectQObjectPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
};
struct instr_loadScopeObjectIntPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
};
struct instr_loadScopeObjectBoolPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
};
struct instr_loadScopeObjectQStringPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
};
struct instr_loadContextObjectProperty {
MOTH_INSTR_HEADER
int propertyIndex;
@ -382,46 +342,6 @@ union Instr
Param result;
bool captureRequired;
};
struct instr_loadQRealQObjectPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
int coreIndex;
int notifyIndex;
};
struct instr_loadQObjectQObjectPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
int coreIndex;
int notifyIndex;
};
struct instr_loadIntQObjectPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
int coreIndex;
int notifyIndex;
};
struct instr_loadBoolQObjectPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
int coreIndex;
int notifyIndex;
};
struct instr_loadQStringQObjectPropertyDirectly {
MOTH_INSTR_HEADER
Param base;
Param result;
QQmlAccessors *accessors;
int coreIndex;
int notifyIndex;
};
struct instr_loadAttachedQObjectProperty {
MOTH_INSTR_HEADER
int propertyIndex;
@ -880,19 +800,9 @@ union Instr
instr_loadProperty loadProperty;
instr_getLookup getLookup;
instr_loadScopeObjectProperty loadScopeObjectProperty;
instr_loadScopeObjectQRealPropertyDirectly loadScopeObjectQRealPropertyDirectly;
instr_loadScopeObjectQObjectPropertyDirectly loadScopeObjectQObjectPropertyDirectly;
instr_loadScopeObjectIntPropertyDirectly loadScopeObjectIntPropertyDirectly;
instr_loadScopeObjectBoolPropertyDirectly loadScopeObjectBoolPropertyDirectly;
instr_loadScopeObjectQStringPropertyDirectly loadScopeObjectQStringPropertyDirectly;
instr_loadContextObjectProperty loadContextObjectProperty;
instr_loadIdObject loadIdObject;
instr_loadQObjectProperty loadQObjectProperty;
instr_loadQRealQObjectPropertyDirectly loadQRealQObjectPropertyDirectly;
instr_loadQObjectQObjectPropertyDirectly loadQObjectQObjectPropertyDirectly;
instr_loadIntQObjectPropertyDirectly loadIntQObjectPropertyDirectly;
instr_loadBoolQObjectPropertyDirectly loadBoolQObjectPropertyDirectly;
instr_loadQStringQObjectPropertyDirectly loadQStringQObjectPropertyDirectly;
instr_loadAttachedQObjectProperty loadAttachedQObjectProperty;
instr_storeProperty storeProperty;
instr_setLookup setLookup;

View File

@ -46,8 +46,6 @@
#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmlengine_p.h>
#include "qml/qqmlaccessors_p.h"
#include "qml/qqmlpropertycache_p.h"
#undef USE_TYPE_INFO
@ -739,51 +737,8 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target
addInstruction(store);
}
void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind,
QQmlPropertyData *property, int index,
IR::Expr *target)
void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target)
{
if (property && property->hasAccessors() && property->isFullyResolved()) {
if (kind == IR::Member::MemberOfQmlScopeObject) {
if (property->propType == QMetaType::QReal) {
Instruction::LoadScopeObjectQRealPropertyDirectly load;
load.base = getParam(source);
load.accessors = property->accessors;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->isQObject()) {
Instruction::LoadScopeObjectQObjectPropertyDirectly load;
load.base = getParam(source);
load.accessors = property->accessors;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->propType == QMetaType::Int) {
Instruction::LoadScopeObjectIntPropertyDirectly load;
load.base = getParam(source);
load.accessors = property->accessors;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->propType == QMetaType::Bool) {
Instruction::LoadScopeObjectBoolPropertyDirectly load;
load.base = getParam(source);
load.accessors = property->accessors;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->propType == QMetaType::QString) {
Instruction::LoadScopeObjectQStringPropertyDirectly load;
load.base = getParam(source);
load.accessors = property->accessors;
load.result = getResultParam(target);
addInstruction(load);
return;
}
}
}
if (kind == IR::Member::MemberOfQmlScopeObject) {
Instruction::LoadScopeObjectProperty load;
load.base = getParam(source);
@ -807,59 +762,8 @@ void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::M
}
}
void InstructionSelection::getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target)
void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target)
{
if (property && property->hasAccessors() && property->isFullyResolved()) {
if (!attachedPropertiesId && !isSingletonProperty) {
if (property->propType == QMetaType::QReal) {
Instruction::LoadQRealQObjectPropertyDirectly load;
load.base = getParam(base);
load.accessors = property->accessors;
load.coreIndex = property->coreIndex;
load.notifyIndex = captureRequired ? property->notifyIndex : -1;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->isQObject()) {
Instruction::LoadQObjectQObjectPropertyDirectly load;
load.base = getParam(base);
load.accessors = property->accessors;
load.coreIndex = property->coreIndex;
load.notifyIndex = captureRequired ? property->notifyIndex : -1;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->propType == QMetaType::Int) {
Instruction::LoadIntQObjectPropertyDirectly load;
load.base = getParam(base);
load.accessors = property->accessors;
load.coreIndex = property->coreIndex;
load.notifyIndex = captureRequired ? property->notifyIndex : -1;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->propType == QMetaType::Bool) {
Instruction::LoadBoolQObjectPropertyDirectly load;
load.base = getParam(base);
load.accessors = property->accessors;
load.coreIndex = property->coreIndex;
load.notifyIndex = captureRequired ? property->notifyIndex : -1;
load.result = getResultParam(target);
addInstruction(load);
return;
} else if (property->propType == QMetaType::QString) {
Instruction::LoadQStringQObjectPropertyDirectly load;
load.base = getParam(base);
load.accessors = property->accessors;
load.coreIndex = property->coreIndex;
load.notifyIndex = captureRequired ? property->notifyIndex : -1;
load.result = getResultParam(target);
addInstruction(load);
return;
}
}
}
const int propertyIndex = property->coreIndex;
if (attachedPropertiesId != 0) {
Instruction::LoadAttachedQObjectProperty load;
load.propertyIndex = propertyIndex;

View File

@ -134,8 +134,8 @@ protected:
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex);
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target);
virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target);
virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target);
virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex);
virtual void copyValue(IR::Expr *source, IR::Expr *target);

View File

@ -156,15 +156,14 @@ void IRDecoder::visitMove(IR::Move *s)
}
}
if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) {
getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property,
m->property->coreIndex, s->target);
getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex, s->target);
return;
}
getQObjectProperty(m->base, m->property, captureRequired, isSingletonProperty, attachedPropertiesId, s->target);
getQObjectProperty(m->base, m->property->coreIndex, captureRequired, isSingletonProperty, attachedPropertiesId, s->target);
#endif // V4_BOOTSTRAP
return;
} else if (m->kind == IR::Member::MemberOfIdObjectsArray) {
getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, nullptr, m->idIndex, s->target);
getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->idIndex, s->target);
return;
} else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) {
getProperty(m->base, *m->name, s->target);

View File

@ -61,7 +61,6 @@
QT_BEGIN_NAMESPACE
class QQmlAccessors;
class QQmlEnginePrivate;
namespace QV4 {
@ -183,8 +182,8 @@ public: // to implement by subclasses:
virtual void setActivationProperty(IR::Expr *source, const QString &targetName) = 0;
virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0;
virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0;
virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0;
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target) = 0;
virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0;
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) = 0;
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0;
virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) = 0;
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0;

View File

@ -370,8 +370,8 @@ Function::Function(Module *module, Function *outer, const QString &name)
, hasWith(false)
, isQmlBinding(false)
, unused(0)
, line(-1)
, column(-1)
, line(0)
, column(0)
, _allBasicBlocks(0)
, _statementCount(0)
{
@ -910,16 +910,12 @@ void IRPrinter::visitMember(Member *e)
visit(e->base);
*out << '.' << *e->name;
#ifndef V4_BOOTSTRAP
if (e->property) {
if (e->property)
*out << " (meta-property " << e->property->coreIndex
<< " <" << QMetaType::typeName(e->property->propType) << ">";
if (e->property->hasAccessors() && e->property->isFullyResolved()) {
*out << ", accessible";
}
*out << ")";
} else if (e->kind == Member::MemberOfIdObjectsArray) {
<< " <" << QMetaType::typeName(e->property->propType)
<< ">)";
else if (e->kind == Member::MemberOfIdObjectsArray)
*out << "(id object " << e->idIndex << ")";
}
#endif
}

View File

@ -1275,9 +1275,9 @@ struct Function {
uint isQmlBinding: 1;
uint unused : 24;
// Location of declaration in source code (-1 if not specified)
int line;
int column;
// Location of declaration in source code (0 if not specified)
uint line;
uint column;
// Qml extension:
SmallSet<int> idObjectDependencies;

View File

@ -642,7 +642,7 @@ public:
qout << from;
else
qout << "(none)";
qout << " -> " << to->index() << endl;
qout << " dominates " << to->index() << endl;
}
qDebug("%s", buf.data().constData());
}
@ -740,6 +740,21 @@ public:
return order;
}
void mergeIntoPredecessor(BasicBlock *successor)
{
int succIdx = successor->index();
if (succIdx == InvalidBasicBlockIndex) {
return;
}
int succDom = idom[unsigned(succIdx)];
for (BasicBlockIndex &idx : idom) {
if (idx == succIdx) {
idx = succDom;
}
}
}
private:
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
@ -1175,6 +1190,15 @@ public:
return _defUses[variable.index].blockOfStatement;
}
void replaceBasicBlock(BasicBlock *from, BasicBlock *to)
{
for (auto &du : _defUses) {
if (du.blockOfStatement == from) {
du.blockOfStatement = to;
}
}
}
void removeUse(Stmt *usingStmt, const Temp &var)
{
Q_ASSERT(static_cast<unsigned>(var.index) < _defUses.size());
@ -3327,6 +3351,15 @@ class BlockScheduler
// this is a loop, where there in -> candidate edge is the jump back to the top of the loop.
continue;
if (in == candidate)
// this is a very tight loop, e.g.:
// L1: ...
// goto L1
// This can happen when, for example, the basic-block merging gets rid of the empty
// body block. In this case, we can safely schedule this block (if all other
// incoming edges are either loop-back edges, or have been scheduled already).
continue;
return false; // an incoming edge that is not yet emitted, and is not a back-edge
}
@ -3709,6 +3742,8 @@ namespace {
void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUses,
StatementWorklist &W, DominatorTree &dt)
{
enum { DebugUnlinking = 0 };
struct Util {
static void removeIncomingEdge(BasicBlock *from, BasicBlock *to, DefUses &defUses, StatementWorklist &W)
{
@ -3747,11 +3782,17 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
}
};
Q_ASSERT(!from->isRemoved());
Q_ASSERT(!to->isRemoved());
// don't purge blocks that are entry points for catch statements. They might not be directly
// connected, but are required anyway
if (to->isExceptionHandler())
return;
if (DebugUnlinking)
qDebug("Unlinking L%d -> L%d...", from->index(), to->index());
// First, unlink the edge
from->out.removeOne(to);
Util::removeIncomingEdge(from, to, defUses, W);
@ -3761,8 +3802,12 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
// Check if the target is still reachable...
if (Util::isReachable(to, dt)) { // yes, recalculate the immediate dominator, and we're done.
if (DebugUnlinking)
qDebug(".. L%d is still reachable, recalulate idom.", to->index());
dt.collectSiblings(to, siblings);
} else {
if (DebugUnlinking)
qDebug(".. L%d is unreachable, purging it:", to->index());
// The target is unreachable, so purge it:
QVector<BasicBlock *> toPurge;
toPurge.reserve(8);
@ -3770,6 +3815,8 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
while (!toPurge.isEmpty()) {
BasicBlock *bb = toPurge.first();
toPurge.removeFirst();
if (DebugUnlinking)
qDebug("... purging L%d", bb->index());
if (bb->isRemoved())
continue;
@ -3813,6 +3860,8 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs
}
dt.recalculateIDoms(siblings);
if (DebugUnlinking)
qDebug("Unlinking done.");
}
bool tryOptimizingComparison(Expr *&expr)
@ -4784,13 +4833,20 @@ static void verifyCFG(IR::Function *function)
Q_ASSERT(function->basicBlock(bb->index()) == bb);
// Check the terminators:
if (Jump *jump = bb->terminator()->asJump()) {
Stmt *terminator = bb->terminator();
if (terminator == nullptr) {
Stmt *last = bb->statements().last();
Call *call = last->asExp()->expr->asCall();
Name *baseName = call->base->asName();
Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
Q_UNUSED(baseName);
} else if (Jump *jump = terminator->asJump()) {
Q_UNUSED(jump);
Q_ASSERT(jump->target);
Q_ASSERT(!jump->target->isRemoved());
Q_ASSERT(bb->out.size() == 1);
Q_ASSERT(bb->out.first() == jump->target);
} else if (CJump *cjump = bb->terminator()->asCJump()) {
} else if (CJump *cjump = terminator->asCJump()) {
Q_UNUSED(cjump);
Q_ASSERT(bb->out.size() == 2);
Q_ASSERT(cjump->iftrue);
@ -4799,7 +4855,7 @@ static void verifyCFG(IR::Function *function)
Q_ASSERT(cjump->iffalse);
Q_ASSERT(!cjump->iffalse->isRemoved());
Q_ASSERT(cjump->iffalse == bb->out[1]);
} else if (bb->terminator()->asRet()) {
} else if (terminator->asRet()) {
Q_ASSERT(bb->out.size() == 0);
} else {
Q_UNREACHABLE();
@ -4934,6 +4990,65 @@ private:
void visitTemp(Temp *) Q_DECL_OVERRIDE Q_DECL_FINAL {}
};
void mergeBasicBlocks(IR::Function *function, DefUses *du, DominatorTree *dt)
{
enum { DebugBlockMerging = 0 };
if (function->hasTry)
return;
showMeTheCode(function, "Before basic block merging");
// Now merge a basic block with its successor when there is one outgoing edge, and the
// successor has one incoming edge.
for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
BasicBlock *bb = function->basicBlock(i);
bb->nextLocation = QQmlJS::AST::SourceLocation(); // make sure appendStatement doesn't mess with the line info
if (bb->isRemoved()) continue; // the block has been removed, so ignore it
if (bb->out.size() != 1) continue; // more than one outgoing edge
BasicBlock *successor = bb->out.first();
if (successor->in.size() != 1) continue; // more than one incoming edge
// Ok, we can merge the two basic blocks.
if (DebugBlockMerging) {
qDebug("Merging L%d into L%d", successor->index(), bb->index());
}
Q_ASSERT(bb->terminator()->asJump());
bb->removeStatement(bb->statementCount() - 1); // remove the terminator, and replace it with:
for (Stmt *s : successor->statements()) {
bb->appendStatement(s); // add all statements from the successor to the current basic block
if (auto cjump = s->asCJump())
cjump->parent = bb;
}
bb->out = successor->out; // set the outgoing edges to the successor's so they're now in sync with our new terminator
for (auto newSuccessor : bb->out) {
for (auto &backlink : newSuccessor->in) {
if (backlink == successor) {
backlink = bb; // for all successors of our successor: set the incoming edges to come from bb, because we'll now jump there.
}
}
}
if (du) {
// all statements in successor have moved to bb, so make sure that the containing blocks
// stored in DefUses get updated (meaning: point to bb)
du->replaceBasicBlock(successor, bb);
}
if (dt) {
// update the immediate dominators to: any block that was dominated by the successor
// will now need to point to bb's immediate dominator. The reason is that bb itself
// won't be anyones immediate dominator, because it had just one outgoing edge.
dt->mergeIntoPredecessor(successor);
}
function->removeBasicBlock(successor);
--i; // re-run on the current basic-block, so any chain gets collapsed.
}
showMeTheCode(function, "After basic block merging");
verifyCFG(function);
}
} // anonymous namespace
void LifeTimeInterval::setFrom(int from) {
@ -5168,6 +5283,8 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA && statementCount <= 300) {
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
mergeBasicBlocks(function, nullptr, nullptr);
ConvertArgLocals(function).toTemps();
showMeTheCode(function, "After converting arguments to locals");
@ -5243,6 +5360,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
}
verifyNoPointerSharing(function);
mergeBasicBlocks(function, &defUses, &df);
// Basic-block cycles that are unreachable (i.e. for loops in a then-part where the
// condition is calculated to be always false) are not yet removed. This will choke the

View File

@ -340,11 +340,6 @@ public:
IR::Expr *value;
};
struct ReentryBlock {
ReentryBlock(IR::BasicBlock *b) : block(b) {}
IR::BasicBlock *block;
};
void callAbsolute(const char* /*functionName*/, const LookupCall &lookupCall)
{
call(lookupCall.addr);
@ -433,13 +428,6 @@ public:
move(source, dest);
}
void loadArgumentInRegister(TrustedImmPtr ptr, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
move(TrustedImmPtr(ptr), dest);
}
void loadArgumentInRegister(const Pointer& ptr, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
@ -449,7 +437,7 @@ public:
void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
loadArgumentInRegister(TrustedImmPtr(0), dest, argumentNumber);
move(TrustedImmPtr(0), dest);
} else {
Pointer addr = toAddress(dest, temp.value, argumentNumber);
loadArgumentInRegister(addr, dest, argumentNumber);
@ -468,15 +456,6 @@ public:
loadArgumentInRegister(addr, dest, argumentNumber);
}
void loadArgumentInRegister(ReentryBlock block, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
Q_ASSERT(block.block);
DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), dest);
addPatch(patch, block.block);
}
#ifdef VALUE_FITS_IN_REGISTER
void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
{
@ -536,11 +515,6 @@ public:
}
#endif
void loadArgumentInRegister(QV4::String* string, RegisterID dest, int argumentNumber)
{
loadArgumentInRegister(TrustedImmPtr(string), dest, argumentNumber);
}
void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
@ -697,34 +671,6 @@ public:
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
template <int StackSlot>
void loadArgumentOnStack(ReentryBlock block, int argumentNumber)
{
Q_UNUSED(argumentNumber);
Q_ASSERT(block.block);
DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), ScratchRegister);
poke(ScratchRegister, StackSlot);
addPatch(patch, block.block);
}
template <int StackSlot>
void loadArgumentOnStack(TrustedImmPtr ptr, int argumentNumber)
{
Q_UNUSED(argumentNumber);
move(TrustedImmPtr(ptr), ScratchRegister);
poke(ScratchRegister, StackSlot);
}
template <int StackSlot>
void loadArgumentOnStack(QV4::String* name, int argumentNumber)
{
Q_UNUSED(argumentNumber);
poke(TrustedImmPtr(name), StackSlot);
}
void loadDouble(IR::Expr *source, FPRegisterID dest)
{
IR::Temp *sourceTemp = source->asTemp();
@ -1146,9 +1092,8 @@ public:
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
static const double magic = double(INT_MAX) + 1;
move(TrustedImmPtr(&magic), scratchReg);
subDouble(Address(scratchReg, 0), FPGpr0);
Address inversionAddress = constantTable().loadValueAddress(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg);
subDouble(inversionAddress, FPGpr0);
Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg);
canNeverHappen.link(this);
or32(TrustedImm32(1 << 31), scratchReg);

View File

@ -49,7 +49,6 @@
#include "qv4assembler_p.h"
#include "qv4unop_p.h"
#include "qv4binop_p.h"
#include <private/qqmlpropertycache_p.h>
#include <QtCore/QBuffer>
#include <QtCore/QCoreApplication>
@ -754,39 +753,8 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::
}
}
void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target)
void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, IR::Expr *target)
{
if (property && property->hasAccessors() && property->isFullyResolved()) {
if (kind == IR::Member::MemberOfQmlScopeObject) {
if (property->propType == QMetaType::QReal) {
generateRuntimeCall(target, accessQmlScopeObjectQRealProperty,
Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors));
return;
} else if (property->isQObject()) {
generateRuntimeCall(target, accessQmlScopeObjectQObjectProperty,
Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors));
return;
} else if (property->propType == QMetaType::Int) {
generateRuntimeCall(target, accessQmlScopeObjectIntProperty,
Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors));
return;
} else if (property->propType == QMetaType::Bool) {
generateRuntimeCall(target, accessQmlScopeObjectBoolProperty,
Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors));
return;
} else if (property->propType == QMetaType::QString) {
generateRuntimeCall(target, accessQmlScopeObjectQStringProperty,
Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors));
return;
}
}
}
if (kind == IR::Member::MemberOfQmlScopeObject)
generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
else if (kind == IR::Member::MemberOfQmlContextObject)
@ -797,51 +765,8 @@ void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::Mem
Q_ASSERT(false);
}
void InstructionSelection::getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
if (property && property->hasAccessors() && property->isFullyResolved()) {
if (!attachedPropertiesId && !isSingleton) {
const int notifyIndex = captureRequired ? property->notifyIndex : -1;
if (property->propType == QMetaType::QReal) {
generateRuntimeCall(target, accessQObjectQRealProperty,
Assembler::EngineRegister, Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors),
Assembler::TrustedImm32(property->coreIndex),
Assembler::TrustedImm32(notifyIndex));
return;
} else if (property->isQObject()) {
generateRuntimeCall(target, accessQObjectQObjectProperty,
Assembler::EngineRegister, Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors),
Assembler::TrustedImm32(property->coreIndex),
Assembler::TrustedImm32(notifyIndex));
return;
} else if (property->propType == QMetaType::Int) {
generateRuntimeCall(target, accessQObjectIntProperty,
Assembler::EngineRegister, Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors),
Assembler::TrustedImm32(property->coreIndex),
Assembler::TrustedImm32(notifyIndex));
return;
} else if (property->propType == QMetaType::Bool) {
generateRuntimeCall(target, accessQObjectBoolProperty,
Assembler::EngineRegister, Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors),
Assembler::TrustedImm32(property->coreIndex),
Assembler::TrustedImm32(notifyIndex));
return;
} else if (property->propType == QMetaType::QString) {
generateRuntimeCall(target, accessQObjectQStringProperty,
Assembler::EngineRegister, Assembler::PointerToValue(base),
Assembler::TrustedImmPtr(property->accessors),
Assembler::TrustedImm32(property->coreIndex),
Assembler::TrustedImm32(notifyIndex));
return;
}
}
}
const int propertyIndex = property->coreIndex;
if (attachedPropertiesId != 0)
generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
else if (isSingleton)

View File

@ -124,8 +124,8 @@ protected:
virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
virtual void initClosure(IR::Closure *closure, IR::Expr *target);
virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target);
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target);
virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target);
virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex);
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);

View File

@ -528,14 +528,14 @@ protected: // IRDecoder
addCall();
}
virtual void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, QQmlPropertyData * /*property*/, int /*index*/, IR::Expr *target)
virtual void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int /*index*/, IR::Expr *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
addCall();
}
virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData * /*property*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target)
virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);

View File

@ -54,7 +54,6 @@
#include "private/qv4isel_p.h"
#include "qv4managed_p.h"
#include "qv4context_p.h"
#include "qv4internalclass_p.h"
#include "qv4runtimeapi_p.h"
#include <private/qintrusivelist_p.h>
@ -86,6 +85,9 @@ namespace CompiledData {
struct CompilationUnit;
}
struct InternalClass;
struct InternalClassPool;
struct Q_QML_EXPORT ExecutionEngine
{
private:

View File

@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
Q_UNUSED(engine);
internalClass = engine->emptyClass;
const quint32 *formalsIndices = compiledFunction->formalsTable();
const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
ScopedString arg(scope);
@ -78,7 +78,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
}
nFormals = compiledFunction->nFormals;
const quint32 *localsIndices = compiledFunction->localsTable();
const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
@ -110,7 +110,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
}
nFormals = parameters.size();
const quint32 *localsIndices = compiledFunction->localsTable();
const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);

View File

@ -101,20 +101,6 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
uint PropertyHash::lookup(const Identifier *identifier) const
{
Q_ASSERT(d->entries);
uint idx = identifier->hashValue % d->alloc;
while (1) {
if (d->entries[idx].identifier == identifier)
return d->entries[idx].index;
if (!d->entries[idx].identifier)
return UINT_MAX;
++idx;
idx %= d->alloc;
}
}
InternalClass::InternalClass(ExecutionEngine *engine)
: engine(engine)
@ -360,18 +346,6 @@ void InternalClass::removeMember(Object *object, Identifier *id)
Q_ASSERT(t.lookup);
}
uint InternalClass::find(const String *string)
{
engine->identifierTable->identifier(string);
const Identifier *id = string->d()->identifier;
uint index = propertyTable.lookup(id);
if (index < size)
return index;
return UINT_MAX;
}
uint InternalClass::find(const Identifier *id)
{
uint index = propertyTable.lookup(id);

View File

@ -54,6 +54,8 @@
#include <QHash>
#include <private/qqmljsmemorypool_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4identifiertable_p.h>
QT_BEGIN_NAMESPACE
@ -117,6 +119,20 @@ inline PropertyHash::~PropertyHash()
delete d;
}
inline uint PropertyHash::lookup(const Identifier *identifier) const
{
Q_ASSERT(d->entries);
uint idx = identifier->hashValue % d->alloc;
while (1) {
if (d->entries[idx].identifier == identifier)
return d->entries[idx].index;
if (!d->entries[idx].identifier)
return UINT_MAX;
++idx;
idx %= d->alloc;
}
}
template <typename T>
struct SharedInternalClassData {
@ -245,7 +261,7 @@ struct InternalClass : public QQmlJS::Managed {
InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0);
static void removeMember(Object *object, Identifier *id);
uint find(const String *s);
uint find(const String *string);
uint find(const Identifier *id);
InternalClass *sealed();
@ -261,6 +277,18 @@ private:
InternalClass(const InternalClass &other);
};
inline uint InternalClass::find(const String *string)
{
engine->identifierTable->identifier(string);
const Identifier *id = string->d()->identifier;
uint index = propertyTable.lookup(id);
if (index < size)
return index;
return UINT_MAX;
}
struct InternalClassPool : public QQmlJS::MemoryPool
{
void markObjects(ExecutionEngine *engine);

View File

@ -56,6 +56,7 @@
#include "qv4engine_p.h"
#include "qv4scopedvalue_p.h"
#include "qv4value_p.h"
#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE

View File

@ -59,7 +59,6 @@
#include <private/qqmldata_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qintrusivelist_p.h>
#include <private/qqmlaccessors_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>

View File

@ -1443,116 +1443,6 @@ ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, con
return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired);
}
template <typename PropertyType>
static inline PropertyType getQObjectProperty(QObject *object, ExecutionEngine *engine, QQmlAccessors *accessors, int coreIndex, int notifyIndex)
{
PropertyType t;
accessors->read(object, &t);
if (notifyIndex != -1) {
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
if (ep && ep->propertyCapture) {
if (accessors->notifier) {
QQmlNotifier *n = nullptr;
accessors->notifier(object, &n);
if (n) {
ep->propertyCapture->captureProperty(n);
}
} else {
ep->propertyCapture->captureProperty(object, coreIndex, notifyIndex);
}
}
}
return t;
}
ReturnedValue Runtime::method_accessQObjectQRealProperty(ExecutionEngine *engine,
const Value &object,
QQmlAccessors *accessors, int coreIndex,
int notifyIndex)
{
auto casted = object.as<QObjectWrapper>();
QObject *o = casted ? casted->object() : nullptr;
if (Q_LIKELY(o)) {
return QV4::Encode(getQObjectProperty<qreal>(o, engine, accessors, coreIndex, notifyIndex));
}
engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
ReturnedValue Runtime::method_accessQObjectQObjectProperty(ExecutionEngine *engine,
const Value &object,
QQmlAccessors *accessors, int coreIndex,
int notifyIndex)
{
auto casted = object.as<QObjectWrapper>();
QObject *o = casted ? casted->object() : nullptr;
if (Q_LIKELY(o)) {
return QV4::QObjectWrapper::wrap(engine, getQObjectProperty<QObject *>(o, engine, accessors,
coreIndex,
notifyIndex));
}
engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
ReturnedValue Runtime::method_accessQObjectIntProperty(ExecutionEngine *engine, const Value &object,
QQmlAccessors *accessors, int coreIndex,
int notifyIndex)
{
auto casted = object.as<QObjectWrapper>();
QObject *o = casted ? casted->object() : nullptr;
if (Q_LIKELY(o)) {
return QV4::Encode(getQObjectProperty<int>(o, engine, accessors, coreIndex, notifyIndex));
}
engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
ReturnedValue Runtime::method_accessQObjectBoolProperty(ExecutionEngine *engine, const Value &object,
QQmlAccessors *accessors, int coreIndex,
int notifyIndex)
{
auto casted = object.as<QObjectWrapper>();
QObject *o = casted ? casted->object() : nullptr;
if (Q_LIKELY(o)) {
return QV4::Encode(getQObjectProperty<bool>(o, engine, accessors, coreIndex, notifyIndex));
}
engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
ReturnedValue Runtime::method_accessQObjectQStringProperty(ExecutionEngine *engine,
const Value &object,
QQmlAccessors *accessors, int coreIndex,
int notifyIndex)
{
auto casted = object.as<QObjectWrapper>();
QObject *o = casted ? casted->object() : nullptr;
if (Q_LIKELY(o)) {
return QV4::Encode(engine->newString(getQObjectProperty<QString>(o, engine, accessors,
coreIndex, notifyIndex)));
}
engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
ReturnedValue Runtime::method_accessQmlScopeObjectQObjectProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
QObject *rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::QObjectWrapper::wrap(c.engine(), rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
QV4::ReturnedValue Runtime::method_getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)
{
QObject *scopeObject = engine->qmlScopeObject();
@ -1934,68 +1824,6 @@ Bool Runtime::method_toBoolean(const Value &value)
return value.toBoolean();
}
ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
qreal rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
int rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
bool rv = false;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine,
const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
QString rv;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(engine->newString(rv));
#else
Q_UNUSED(engine);
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
#endif // V4_BOOTSTRAP
} // namespace QV4

View File

@ -56,11 +56,6 @@
#include "qv4engine_p.h"
#include "qv4math_p.h"
#include "qv4runtimeapi_p.h"
#ifndef V4_BOOTSTRAP
#include <private/qqmlaccessors_p.h>
#include <private/qqmlcontextwrapper_p.h>
#endif
#include <QtCore/qnumeric.h>
QT_BEGIN_NAMESPACE

View File

@ -167,16 +167,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
, INIT_RUNTIME_METHOD(setQmlScopeObjectProperty)
, INIT_RUNTIME_METHOD(setQmlContextObjectProperty)
, INIT_RUNTIME_METHOD(setQmlQObjectProperty)
, INIT_RUNTIME_METHOD(accessQObjectQRealProperty)
, INIT_RUNTIME_METHOD(accessQObjectQObjectProperty)
, INIT_RUNTIME_METHOD(accessQObjectIntProperty)
, INIT_RUNTIME_METHOD(accessQObjectBoolProperty)
, INIT_RUNTIME_METHOD(accessQObjectQStringProperty)
, INIT_RUNTIME_METHOD(accessQmlScopeObjectQRealProperty)
, INIT_RUNTIME_METHOD(accessQmlScopeObjectQObjectProperty)
, INIT_RUNTIME_METHOD(accessQmlScopeObjectIntProperty)
, INIT_RUNTIME_METHOD(accessQmlScopeObjectBoolProperty)
, INIT_RUNTIME_METHOD(accessQmlScopeObjectQStringProperty)
{ }
// call
@ -313,17 +303,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
RUNTIME_METHOD(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
RUNTIME_METHOD(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
RUNTIME_METHOD(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value));
RUNTIME_METHOD(ReturnedValue, accessQObjectQRealProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
RUNTIME_METHOD(ReturnedValue, accessQObjectQObjectProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
RUNTIME_METHOD(ReturnedValue, accessQObjectIntProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
RUNTIME_METHOD(ReturnedValue, accessQObjectBoolProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
RUNTIME_METHOD(ReturnedValue, accessQObjectQStringProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex));
RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQRealProperty, (const Value &context, QQmlAccessors *accessors));
RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQObjectProperty, (const Value &context, QQmlAccessors *accessors));
RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectIntProperty, (const Value &context, QQmlAccessors *accessors));
RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectBoolProperty, (const Value &context, QQmlAccessors *accessors));
RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQStringProperty, (ExecutionEngine *engine, const Value &context, QQmlAccessors *accessors));
};
#undef RUNTIME_METHOD

View File

@ -46,59 +46,10 @@
#include "qv4stringobject_p.h"
#endif
#include <QtCore/QHash>
#include <QtCore/private/qnumeric_p.h>
using namespace QV4;
static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
#ifndef V4_BOOTSTRAP
static inline uint toUInt(const char *ch) { return *ch; }
#endif
template <typename T>
static inline uint toArrayIndex(const T *ch, const T *end)
{
uint i = toUInt(ch) - '0';
if (i > 9)
return UINT_MAX;
++ch;
// reject "01", "001", ...
if (i == 0 && ch != end)
return UINT_MAX;
while (ch < end) {
uint x = toUInt(ch) - '0';
if (x > 9)
return UINT_MAX;
if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i))
return UINT_MAX;
++ch;
}
return i;
}
#ifndef V4_BOOTSTRAP
template <typename T>
static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
{
// array indices get their number as hash value
uint h = ::toArrayIndex(ch, end);
if (h != UINT_MAX) {
if (subtype)
*subtype = Heap::String::StringType_ArrayIndex;
return h;
}
while (ch < end) {
h = 31 * h + toUInt(ch);
++ch;
}
if (subtype)
*subtype = Heap::String::StringType_Regular;
return h;
}
DEFINE_MANAGED_VTABLE(String);
@ -225,19 +176,7 @@ void Heap::String::createHashValue() const
Q_ASSERT(!largestSubLength);
const QChar *ch = reinterpret_cast<const QChar *>(text->data());
const QChar *end = ch + text->size;
stringHash = calculateHashValue(ch, end, &subtype);
}
uint String::createHashValue(const QChar *ch, int length, uint *subtype)
{
const QChar *end = ch + length;
return calculateHashValue(ch, end, subtype);
}
uint String::createHashValue(const char *ch, int length, uint *subtype)
{
const char *end = ch + length;
return calculateHashValue(ch, end, subtype);
stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
}
uint String::getLength(const Managed *m)
@ -249,6 +188,6 @@ uint String::getLength(const Managed *m)
uint String::toArrayIndex(const QString &str)
{
return ::toArrayIndex(str.constData(), str.constData() + str.length());
return QV4::String::toArrayIndex(str.constData(), str.constData() + str.length());
}

View File

@ -52,6 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4managed_p.h"
#include <QtCore/private/qnumeric_p.h>
QT_BEGIN_NAMESPACE
@ -62,7 +63,6 @@ struct Identifier;
namespace Heap {
#ifndef V4_BOOTSTRAP
struct Q_QML_PRIVATE_EXPORT String : Base {
enum StringType {
StringType_Unknown,
@ -70,6 +70,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
StringType_ArrayIndex
};
#ifndef V4_BOOTSTRAP
String(MemoryManager *mm, const QString &text);
String(MemoryManager *mm, String *l, String *n);
~String() {
@ -130,8 +131,8 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
MemoryManager *mm;
private:
static void append(const String *data, QChar *ch);
};
#endif
};
}
@ -183,8 +184,17 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
void makeIdentifierImpl(ExecutionEngine *e) const;
static uint createHashValue(const QChar *ch, int length, uint *subtype);
static uint createHashValue(const char *ch, int length, uint *subtype);
static uint createHashValue(const QChar *ch, int length, uint *subtype)
{
const QChar *end = ch + length;
return calculateHashValue(ch, end, subtype);
}
static uint createHashValue(const char *ch, int length, uint *subtype)
{
const char *end = ch + length;
return calculateHashValue(ch, end, subtype);
}
bool startsWithUpper() const {
const String::Data *l = d();
@ -203,6 +213,54 @@ protected:
public:
static uint toArrayIndex(const QString &str);
private:
static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
static inline uint toUInt(const char *ch) { return *ch; }
template <typename T>
static inline uint toArrayIndex(const T *ch, const T *end)
{
uint i = toUInt(ch) - '0';
if (i > 9)
return UINT_MAX;
++ch;
// reject "01", "001", ...
if (i == 0 && ch != end)
return UINT_MAX;
while (ch < end) {
uint x = toUInt(ch) - '0';
if (x > 9)
return UINT_MAX;
if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
return UINT_MAX;
++ch;
}
return i;
}
public:
template <typename T>
static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
{
// array indices get their number as hash value
uint h = toArrayIndex(ch, end);
if (h != UINT_MAX) {
if (subtype)
*subtype = Heap::String::StringType_ArrayIndex;
return h;
}
while (ch < end) {
h = 31 * h + toUInt(ch);
++ch;
}
if (subtype)
*subtype = Heap::String::StringType_Regular;
return h;
}
};
template<>

View File

@ -519,26 +519,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
STOREVALUE(instr.result, engine->runtime.getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadQObjectProperty)
MOTH_BEGIN_INSTR(LoadQRealQObjectPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQObjectQRealProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
MOTH_END_INSTR(LoadQRealQObjectPropertyDirectly)
MOTH_BEGIN_INSTR(LoadQObjectQObjectPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQObjectQObjectProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
MOTH_END_INSTR(LoadQObjectQObjectPropertyDirectly)
MOTH_BEGIN_INSTR(LoadIntQObjectPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQObjectIntProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
MOTH_END_INSTR(LoadIntQObjectPropertyDirectly)
MOTH_BEGIN_INSTR(LoadBoolQObjectPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQObjectBoolProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
MOTH_END_INSTR(LoadQRealQObjectPropertyDirectly)
MOTH_BEGIN_INSTR(LoadQStringQObjectPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQObjectQStringProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex));
MOTH_END_INSTR(LoadQStringQObjectPropertyDirectly)
MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
engine->runtime.setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
@ -548,26 +528,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex));
MOTH_END_INSTR(LoadScopeObjectProperty)
MOTH_BEGIN_INSTR(LoadScopeObjectQRealPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQRealProperty(VALUE(instr.base), instr.accessors));
MOTH_END_INSTR(LoadScopeObjectQRealPropertyDirectly)
MOTH_BEGIN_INSTR(LoadScopeObjectQObjectPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQObjectProperty(VALUE(instr.base), instr.accessors));
MOTH_END_INSTR(LoadScopeObjectQObjectPropertyDirectly)
MOTH_BEGIN_INSTR(LoadScopeObjectIntPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectIntProperty(VALUE(instr.base), instr.accessors));
MOTH_END_INSTR(LoadScopeObjectIntPropertyDirectly)
MOTH_BEGIN_INSTR(LoadScopeObjectBoolPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectBoolProperty(VALUE(instr.base), instr.accessors));
MOTH_END_INSTR(LoadScopeObjectBoolPropertyDirectly)
MOTH_BEGIN_INSTR(LoadScopeObjectQStringPropertyDirectly)
STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQStringProperty(engine, VALUE(instr.base), instr.accessors));
MOTH_END_INSTR(LoadScopeObjectQStringPropertyDirectly)
MOTH_BEGIN_INSTR(StoreContextObjectProperty)
engine->runtime.setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;

View File

@ -39,30 +39,7 @@
#include "qhashedstring_p.h"
inline quint32 stringHash(const QChar* data, int length)
{
return QV4::String::createHashValue(data, length, Q_NULLPTR);
}
inline quint32 stringHash(const char *data, int length)
{
return QV4::String::createHashValue(data, length, Q_NULLPTR);
}
void QHashedString::computeHash() const
{
m_hash = stringHash(constData(), length());
}
void QHashedStringRef::computeHash() const
{
m_hash = stringHash(m_data, m_length);
}
void QHashedCStringRef::computeHash() const
{
m_hash = stringHash(m_data, m_length);
}
/*
A QHash has initially around pow(2, MinNumBits) buckets. For

View File

@ -85,11 +85,15 @@ public:
static bool compare(const QChar *lhs, const QChar *rhs, int length);
static inline bool compare(const QChar *lhs, const char *rhs, int length);
static inline bool compare(const char *lhs, const char *rhs, int length);
static inline quint32 stringHash(const QChar* data, int length);
static inline quint32 stringHash(const char *data, int length);
private:
friend class QHashedStringRef;
friend class QStringHashNode;
void computeHash() const;
inline void computeHash() const;
mutable quint32 m_hash;
};
@ -136,7 +140,7 @@ public:
private:
friend class QHashedString;
void computeHash() const;
inline void computeHash() const;
const QChar *m_data;
int m_length;
@ -163,7 +167,7 @@ public:
private:
friend class QHashedStringRef;
void computeHash() const;
inline void computeHash() const;
const char *m_data;
int m_length;
@ -1214,6 +1218,11 @@ bool QHashedStringRef::isLatin1() const
return true;
}
void QHashedStringRef::computeHash() const
{
m_hash = QHashedString::stringHash(m_data, m_length);
}
bool QHashedStringRef::startsWithUpper() const
{
if (m_length < 1) return false;
@ -1280,6 +1289,11 @@ void QHashedCStringRef::writeUtf16(quint16 *output) const
*output++ = *d++;
}
void QHashedCStringRef::computeHash() const
{
m_hash = QHashedString::stringHash(m_data, m_length);
}
bool QHashedString::compare(const QChar *lhs, const char *rhs, int length)
{
Q_ASSERT(lhs && rhs);
@ -1295,6 +1309,21 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length)
return 0 == ::memcmp(lhs, rhs, length);
}
quint32 QHashedString::stringHash(const QChar *data, int length)
{
return QV4::String::createHashValue(data, length, Q_NULLPTR);
}
quint32 QHashedString::stringHash(const char *data, int length)
{
return QV4::String::createHashValue(data, length, Q_NULLPTR);
}
void QHashedString::computeHash() const
{
m_hash = stringHash(constData(), length());
}
QT_END_NAMESPACE
#endif // QHASHEDSTRING_P_H

View File

@ -91,6 +91,8 @@ public:
inline QQmlAbstractBinding *nextBinding() const;
inline bool canUseAccessor() const
{ return m_nextBinding.flag2(); }
struct RefCount {
RefCount() : refCount(0) {}
@ -112,8 +114,15 @@ protected:
inline void setNextBinding(QQmlAbstractBinding *);
int m_targetIndex;
// Pointer is the target object to which the binding binds
// flag1 is the updating flag
// flag2 is the enabled flag
QFlagPointer<QObject> m_target;
// Pointer to the next binding in the linked list of bindings.
// flag1 is used for addedToObject
// flag2 indicates if an accessor is can be used (i.e. there is no interceptor on the target)
QFlagPointer<QQmlAbstractBinding> m_nextBinding;
};

View File

@ -102,11 +102,15 @@ class QQmlNotifier;
} \
} while (false);
#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \
#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable, setter) \
static void clazz ## _ ## name ## Read(QObject *o, void *rv) \
{ \
clazz ## Private *d = clazz ## Private::get(static_cast<clazz *>(o)); \
*static_cast<cpptype *>(rv) = d->variable; \
} \
static void clazz ## _ ## name ## Write(QObject *o, void *rv) \
{ \
static_cast<clazz *>(o)->setter(*static_cast<cpptype *>(rv)); \
}
#define QML_PROPERTY_NAME(name) #name, sizeof #name - 1
@ -115,6 +119,7 @@ class QQmlAccessors
{
public:
void (*read)(QObject *object, void *output);
void (*write)(QObject *object, void *output);
void (*notifier)(QObject *object, QQmlNotifier **notifier);
};

View File

@ -43,6 +43,7 @@
#include "qqmlcontext.h"
#include "qqmlinfo.h"
#include "qqmldata_p.h"
#include "qqmlaccessors_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
@ -210,21 +211,10 @@ protected:
}
};
#define QUICK_STORE(cpptype, conversion) \
{ \
cpptype o = (conversion); \
int status = -1; \
void *argv[] = { &o, 0, &status, &flags }; \
QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, coreIndex, argv); \
return true; \
} \
template<int StaticPropType>
class GenericBinding: public QQmlBinding
{
protected:
void doUpdate(QQmlBinding *binding, const DeleteWatcher &watcher,
QQmlPropertyPrivate::WriteFlags flags, QV4::Scope &scope,
const QV4::ScopedFunctionObject &f) Q_DECL_OVERRIDE Q_DECL_FINAL
@ -238,13 +228,8 @@ protected:
binding->QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope);
bool error = false;
if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) {
if (StaticPropType == QMetaType::UnknownType) {
error = !write(scope.result, isUndefined, flags);
} else {
error = !fastWrite(scope.result, isUndefined, flags);
}
}
if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
error = !write(scope.result, isUndefined, flags);
if (!watcher.wasDeleted()) {
@ -264,99 +249,72 @@ protected:
ep->dereferenceScarceResources();
}
private:
// Returns true if successful, false if an error description was set on expression
Q_ALWAYS_INLINE bool fastWrite(const QV4::Value &result, bool isUndefined,
QQmlPropertyPrivate::WriteFlags flags)
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
QQmlPropertyPrivate::WriteFlags flags)
{
int coreIndex = getPropertyCoreIndex();
QQmlPropertyData pd = getPropertyData();
int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
if (propertyType == QMetaType::UnknownType)
propertyType = pd.propType;
Q_ASSERT(targetObject());
Q_ASSERT(m_target.data());
if (Q_LIKELY(!isUndefined && coreIndex != -1 )) {
switch (StaticPropType) {
if (Q_LIKELY(!isUndefined && !pd.isValueTypeVirtual())) {
switch (propertyType) {
case QMetaType::Bool:
if (result.isBoolean())
return doStore<bool>(result.booleanValue(), pd, flags);
else
return doStore<bool>(result.toBoolean(), pd, flags);
case QMetaType::Int:
if (result.isInteger())
QUICK_STORE(int, result.integerValue())
return doStore<int>(result.integerValue(), pd, flags);
else if (result.isNumber())
QUICK_STORE(int, result.doubleValue())
return doStore<int>(result.doubleValue(), pd, flags);
break;
case QMetaType::Double:
if (result.isNumber())
QUICK_STORE(double, result.asDouble())
return doStore<double>(result.asDouble(), pd, flags);
break;
case QMetaType::Float:
if (result.isNumber())
QUICK_STORE(float, result.asDouble())
return doStore<float>(result.asDouble(), pd, flags);
break;
case QMetaType::QString:
if (result.isString())
QUICK_STORE(QString, result.toQStringNoThrow())
return doStore<QString>(result.toQStringNoThrow(), pd, flags);
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
if (vtw->d()->valueType->typeId == StaticPropType) {
return vtw->write(m_target.data(), coreIndex);
if (vtw->d()->valueType->typeId == pd.propType) {
return vtw->write(m_target.data(), pd.coreIndex);
}
}
break;
}
}
return slowWrite(result, isUndefined, flags);
return slowWrite(pd, result, isUndefined, flags);
}
template <typename T>
Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData &pd, QQmlPropertyPrivate::WriteFlags flags) const
{
void *o = &value;
if (pd.hasAccessors() && canUseAccessor()) {
pd.accessors->write(m_target.data(), o);
} else {
int status = -1;
void *argv[] = { o, 0, &status, &flags };
QMetaObject::metacall(targetObject(), QMetaObject::WriteProperty, pd.coreIndex, argv);
}
return true;
}
};
// Returns true if successful, false if an error description was set on expression
Q_ALWAYS_INLINE bool QQmlBinding::write(const QV4::Value &result, bool isUndefined,
QQmlPropertyPrivate::WriteFlags flags)
Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core, const QV4::Value &result,
bool isUndefined, QQmlPropertyPrivate::WriteFlags flags)
{
Q_ASSERT(m_target.data());
int coreIndex = getPropertyCoreIndex();
int propertyType = getPropertyType();
Q_ASSERT(m_target.data());
if (Q_LIKELY(!isUndefined && coreIndex != -1 )) {
switch (propertyType) {
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 == propertyType) {
return vtw->write(m_target.data(), coreIndex);
}
}
break;
}
}
return slowWrite(result, isUndefined, flags);
}
#undef QUICK_STORE
Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QV4::Value &result, bool isUndefined,
QQmlPropertyPrivate::WriteFlags flags)
{
QQmlPropertyData core = getPropertyData();
QQmlEngine *engine = context()->engine;
QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
@ -505,6 +463,13 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
setEnabledFlag(e);
setNotifyOnValueChanged(e);
m_nextBinding.clearFlag2();
if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
int coreIndex = getPropertyCoreIndex();
if (coreIndex != -1 && !interceptorMetaObject->intercepts(coreIndex))
m_nextBinding.setFlag2();
}
if (e)
update(flags);
}
@ -611,38 +576,26 @@ Q_ALWAYS_INLINE int QQmlBinding::getPropertyCoreIndex() const
}
}
int QQmlBinding::getPropertyType() const
{
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);
if (valueTypeIndex == -1)
return propertyData->propType;
else
return QMetaType::UnknownType;
}
QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property)
{
const int type = (property && property->isFullyResolved()) ? property->propType : QMetaType::UnknownType;
if (type == qMetaTypeId<QQmlBinding *>()) {
return new QQmlBindingBinding;
} else if (type == QMetaType::Int) {
}
switch (type) {
case QMetaType::Bool:
return new GenericBinding<QMetaType::Bool>;
case QMetaType::Int:
return new GenericBinding<QMetaType::Int>;
} else if (type == QMetaType::Double) {
case QMetaType::Double:
return new GenericBinding<QMetaType::Double>;
} else if (type == QMetaType::Float) {
case QMetaType::Float:
return new GenericBinding<QMetaType::Float>;
} else if (type == QMetaType::QString) {
case QMetaType::QString:
return new GenericBinding<QMetaType::QString>;
} else {
default:
return new GenericBinding<QMetaType::UnknownType>;
}
}

View File

@ -110,9 +110,7 @@ protected:
int getPropertyCoreIndex() const;
int getPropertyType() const;
bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyPrivate::WriteFlags flags);
bool slowWrite(const QV4::Value &result, bool isUndefined,
bool slowWrite(const QQmlPropertyData &core, const QV4::Value &result, bool isUndefined,
QQmlPropertyPrivate::WriteFlags flags);
private:

View File

@ -312,7 +312,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext());
QQmlContextData *qmlContext = context->qmlContext();
const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) {
Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount);
@ -321,7 +321,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
}
Q_ASSERT(qmlContext->contextObject);
const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
for (int i = 0; i < contextPropertyDependencyCount; ++i) {
const int propertyIndex = *contextPropertyDependency++;
@ -331,7 +331,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
}
QObject *scopeObject = context->qmlScope();
const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
for (int i = 0; i < scopePropertyDependencyCount; ++i) {
const int propertyIndex = *scopePropertyDependency++;

View File

@ -54,6 +54,7 @@
#include <private/qqmlscriptstring_p.h>
#include <private/qqmlpropertyvalueinterceptor_p.h>
#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmlaccessors_p.h>
QT_USE_NAMESPACE
@ -342,8 +343,12 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::String: {
Q_ASSERT(binding->evaluatesToString());
QString value = binding->valueAsString(qmlUnit);
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
if (property->hasAccessors()) {
property->accessors->write(_qobject, &value);
} else {
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
}
break;
case QVariant::StringList: {
@ -386,23 +391,35 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double d = binding->valueAsNumber();
int value = int(d);
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
if (property->hasAccessors()) {
property->accessors->write(_qobject, &value);
} else {
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
break;
}
break;
case QMetaType::Float: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
float value = float(binding->valueAsNumber());
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
if (property->hasAccessors()) {
property->accessors->write(_qobject, &value);
} else {
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
}
break;
case QVariant::Double: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
double value = binding->valueAsNumber();
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
if (property->hasAccessors()) {
property->accessors->write(_qobject, &value);
} else {
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
}
break;
case QVariant::Color: {
@ -499,8 +516,12 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::Bool: {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
bool value = binding->valueAsBoolean();
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
if (property->hasAccessors()) {
property->accessors->write(_qobject, &value);
} else {
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
}
}
break;
case QVariant::Vector3D: {
@ -979,7 +1000,7 @@ void QQmlObjectCreator::setupFunctions()
QV4::ScopedValue function(scope);
QV4::ScopedContext qmlContext(scope, currentQmlContext());
const quint32 *functionIdx = _compiledObject->functionOffsetTable();
const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable();
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString();

View File

@ -230,9 +230,10 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
flags |= NotFullyResolved;
}
if (m.parameterCount()) {
const int paramCount = m.parameterCount();
if (paramCount) {
flags |= HasArguments;
if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
if ((paramCount == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
flags |= IsV4Function;
}
}
@ -423,12 +424,6 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
// Returns this property cache's metaObject. May be null if it hasn't been created yet.
const QMetaObject *QQmlPropertyCache::metaObject() const
{
return _metaObject;
}
// Returns this property cache's metaObject, creating it if necessary.
const QMetaObject *QQmlPropertyCache::createMetaObject()
{
@ -444,22 +439,11 @@ const QMetaObject *QQmlPropertyCache::createMetaObject()
return _metaObject;
}
// Returns the name of the default property for this cache
QString QQmlPropertyCache::defaultPropertyName() const
{
return _defaultPropertyName;
}
QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
return property(defaultPropertyName(), 0, 0);
}
QQmlPropertyCache *QQmlPropertyCache::parent() const
{
return _parent;
}
void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
{
if (_parent == newParent)
@ -470,15 +454,6 @@ void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
_parent->addref();
}
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
// QML
const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
{
while (_parent && (_metaObject == 0 || _ownMetaObject))
return _parent->firstCppMetaObject();
return _metaObject;
}
QQmlPropertyCache *
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
QQmlPropertyData::Flag propertyFlags,
@ -535,11 +510,12 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
bool hasFastProperty = false;
for (int ii = 0; ii < classInfoCount; ++ii) {
int idx = ii + classInfoOffset;
if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
QMetaClassInfo mci = metaObject->classInfo(idx);
const char *name = mci.name();
if (0 == qstrcmp(name, "qt_HasQmlAccessors")) {
hasFastProperty = true;
} else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
_defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
} else if (0 == qstrcmp(name, "DefaultProperty")) {
_defaultPropertyName = QString::fromUtf8(mci.value());
}
}
@ -814,48 +790,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
QQmlPropertyData *
QQmlPropertyCache::signal(int index) const
{
if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
return 0;
if (index < signalHandlerIndexCacheStart)
return _parent->signal(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
return ensureResolved(rv);
}
int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
{
if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
return index;
if (index < methodIndexCacheStart)
return _parent->methodIndexToSignalIndex(index);
return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
}
QQmlPropertyData *
QQmlPropertyCache::method(int index) const
{
if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
return 0;
if (index < methodIndexCacheStart)
return _parent->method(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
return ensureResolved(rv);
}
QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
{
QQmlData *data = (object ? QQmlData::get(object) : 0);
@ -872,11 +806,11 @@ inline bool contextHasNoExtensions(QQmlContextData *context)
return (!context->parent || !context->parent->imports);
}
inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
{
return (prop->isFunction() ? vmemo->methodCount()
: prop->isSignalHandler() ? vmemo->signalCount()
: vmemo->propertyCount());
return prop->isFunction() ? methodCount
: prop->isSignalHandler() ? signalCount
: propertyCount;
}
}
@ -903,11 +837,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
}
if (vmemo) {
const int methodCount = vmemo->methodCount();
const int signalCount = vmemo->signalCount();
const int propertyCount = vmemo->propertyCount();
// Ensure that the property we resolve to is accessible from this meta-object
do {
const StringCache::mapped_type &property(it.value());
if (property.first < maximumIndexForProperty(property.second, vmemo)) {
if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
// This property is available in the specified context
if (property.second->isFunction() || property.second->isSignalHandler()) {
// Prefer the earlier resolution

View File

@ -73,6 +73,7 @@ class QMetaObjectBuilder;
class QQmlPropertyCacheMethodArguments;
class QQmlVMEMetaObject;
template <typename T> class QQmlPropertyCacheCreator;
template <typename T> class QQmlPropertyCacheAliasCreator;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
@ -338,6 +339,7 @@ private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
template <typename T> friend class QQmlPropertyCacheCreator;
template <typename T> friend class QQmlPropertyCacheAliasCreator;
friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
@ -526,6 +528,21 @@ inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p)
return p;
}
// Returns this property cache's metaObject. May be null if it hasn't been created yet.
inline const QMetaObject *QQmlPropertyCache::metaObject() const
{
return _metaObject;
}
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
// QML
inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
{
while (_parent && (_metaObject == 0 || _ownMetaObject))
return _parent->firstCppMetaObject();
return _metaObject;
}
inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
@ -538,6 +555,57 @@ inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
return ensureResolved(rv);
}
inline QQmlPropertyData *QQmlPropertyCache::method(int index) const
{
if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
return 0;
if (index < methodIndexCacheStart)
return _parent->method(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
return ensureResolved(rv);
}
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
{
if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
return 0;
if (index < signalHandlerIndexCacheStart)
return _parent->signal(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
return ensureResolved(rv);
}
inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
{
if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
return index;
if (index < methodIndexCacheStart)
return _parent->methodIndexToSignalIndex(index);
return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
}
// Returns the name of the default property for this cache
inline QString QQmlPropertyCache::defaultPropertyName() const
{
return _defaultPropertyName;
}
inline QQmlPropertyCache *QQmlPropertyCache::parent() const
{
return _parent;
}
QQmlPropertyData *
QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
{

View File

@ -630,7 +630,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= propOffset();
if (id < propertyCount) {
const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(compiledObject->propertyTable()[id].type);
const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type));
bool needActivate = false;
if (t == QV4::CompiledData::Property::Var) {
@ -845,6 +845,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (!ctxt) return -1;
while (aliasData->aliasToLocalAlias)
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);

View File

@ -72,6 +72,7 @@
#include <private/qv4object_p.h>
#include <private/qv4value_p.h>
#include <private/qqmlpropertyvalueinterceptor_p.h>
QT_BEGIN_NAMESPACE
@ -105,6 +106,15 @@ public:
// Used by auto-tests for inspection
QQmlPropertyCache *propertyCache() const { return cache; }
bool intercepts(int coreIndex) const
{
for (auto it = interceptors; it; it = it->m_next) {
if (it->m_coreIndex == coreIndex)
return true;
}
return false;
}
protected:
int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) Q_DECL_OVERRIDE;
bool intercept(QMetaObject::Call c, int id, void **a);

View File

@ -127,9 +127,6 @@ It is not possible to render particle effects with the Software adaptation. When
possible, remove particles completely from the scene. Otherwise they will still
require some processing, even though they are not visible.
\section2 Sprites
The Sprite item depends on OpenGL functions and will not be visible.
\section2 Rendering Text
The text rendering with the Software adaptation is based on software
rasterization and does not respond as well to transformations such as scaling
@ -243,8 +240,8 @@ GraphicsInfo.shaderCompilationType and GraphicsInfo.shaderSourceType.
Unlike OpenGL, there is a QFileSelector with the extra selector \c hlsl used
whenever opening a file. This allows easy creation of ShaderEffect items that
are functional across both backends, for example by placing the GLSL source
code into "shaders/effect.frag", the HLSL source code or - preferably -
pre-compiled bytecode into "shaders/+hlsl/effect.frag", while simply writing
code into \c{shaders/effect.frag}, the HLSL source code or - preferably -
pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
\c{fragmentShader: "qrc:shaders/effect.frag"} in QML.
See the ShaderEffect documentation for more details.
@ -252,12 +249,29 @@ See the ShaderEffect documentation for more details.
\section2 Multisample Render Targets
The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow
or QQuickView (or set via QSurfaceFormat::setDefaultFormat()), with one
exception: QSurfaceFormat::samples() is still taken into account. When the
value is greater than 1, multisample offscreen render targets will be created
with the specified sample count and a quality of the maximum supported quality
level. The backend automatically performs resolving into the non-multisample
swapchain buffers after each frame.
or QQuickView (or set via QSurfaceFormat::setDefaultFormat()), with two
exceptions: QSurfaceFormat::samples() and QSurfaceFormat::alphaBufferSize() are
still taken into account. When the samples value is greater than 1, multisample
offscreen render targets will be created with the specified sample count and a
quality of the maximum supported quality level. The backend automatically
performs resolving into the non-multisample swapchain buffers after each frame.
\section2 Semi-transparent windows
When the alpha channel is enabled either via
QQuickWindow::setDefaultAlphaBuffer() or by setting alphaBufferSize to a
non-zero value in the window's QSurfaceFormat or in the global format managed
by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a
swapchain for composition and go through DirectComposition since the flip model
swapchain (which is mandatory) would not support transparency otherwise.
It is therefore important not to unneccessarily request an alpha channel. When
the alphaBufferSize is 0 or the default -1, all these extra steps can be
avoided and the traditional window-based swapchain is sufficient.
This is not relevant on WinRT because there the backend always uses a
composition swapchain which is associated with the ISwapChainPanel that backs
QWindow on that platform.
\section2 Mipmaps
@ -277,13 +291,17 @@ conversion on the CPU first.
\section2 Unsupported Features
Particles, sprites, and other OpenGL-dependent tools like
QQuickFramebufferObject are not currently supported.
Particles and some other OpenGL-dependent utilities, like
QQuickFramebufferObject, are not currently supported.
Like with the \l{qtquick-visualcanvas-adaptations-software.html}{Software
adaptation}, text is always rendered using the native method. Distance
field-based text rendering is not currently implemented.
The shader sources in the \l {Qt Graphical Effects} module have not been ported
to any format other than the OpenGL 2.0 compatible one, meaning the QML types
provided by that module are not currently functional with the D3D12 backend.
Texture atlases are not currently in use.
The renderer may lack support for certain minor features, for example drawing
@ -293,6 +311,11 @@ Custom Qt Quick items using custom scenegraph nodes can be problematic.
Materials are inherently tied to the graphics API. Therefore only items using
the utility rectangle and image nodes are functional across all adaptations.
QQuickWidget and its underlying OpenGL-based compositing architecture is not
supported. If mixing with QWidget-based user interfaces is desired, use
QWidget::createWindowContainer() to embed the native window of the QQuickWindow
or QQuickView.
Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with
the D3D12 adaptation at the moment.
@ -321,7 +344,8 @@ QQuickWindow::createRectangleNode() and QQuickWindow::createImageNode().
The D3D12 adaptation can keep multiple frames in flight, similarly to modern
game engines. This is somewhat different from the traditional render - swap -
wait for vsync model and allows better GPU utilization at the expense of higher
resource usage.
resource usage. This means that the renderer will be a number of frames ahead
of what is displayed on the screen.
For a discussion of flip model swap chains and the typical configuration
parameters, refer to
@ -335,25 +359,31 @@ The configuration can be changed by setting the following environment variables:
\list
\li \c{QT_D3D_BUFFER_COUNT} - The number of swap chain buffers. Defaults to 3.
\li \c{QT_D3D_BUFFER_COUNT} - The number of swap chain buffers in range 2 - 4.
The default value is 3.
\li \c{QT_D3D_FRAME_COUNT} - The number of frames prepared without blocking.
Defaults to 2. Note that Present will start blocking after queuing 3 frames
\li \c{QT_D3D_FRAME_COUNT} - The number of frames prepared without blocking in
range 1 - 4. Note that Present will start blocking after queuing 3 frames
(regardless of \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use.
Note that every additional frame increases GPU resource usage since geometry
and constant buffer data will have to be duplicated, and involves more
bookkeeping on the CPU side.
bookkeeping on the CPU side. The default value is 2.
\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} - When set, the frame latency is
set to the specified value (0-16). This changes the limit for Present() and
will trigger a wait for an available swap chain buffer when beginning each
frame. By default this is disabled. Refer to the article above for a detailed
discussion.
\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} - When set to a value between 1
and 16, the frame latency is set to the specified value. This changes the limit
for Present() and will trigger a wait for an available swap chain buffer when
beginning each frame. Refer to the article above for a detailed discussion.
This is considered experimental for now and the default value is 0 (disabled).
\li \c{QT_D3D_BLOCKING_PRESENT} - When set to a non-zero value, there will be
CPU-side wait for the GPU to finish its work after each call to Present. This
effectively kills all parallelism but makes the behavior resemble the
traditional swap-blocks-for-vsync model, and can therefore be useful in some
special cases. This is not the same as setting the frame count to 1 because
that still avoids blocking after Present, and may block only when starting to
prepare the next frame (or may not block at all depending on the time gap
between the frames). By default blocking present is disabled.
\endlist
Note that typical Qt Quick applications are expected to generate fairly low
workloads compared to true 3D applications like games. Therefore this level of
tuning will likely be unnecessary in most cases.
*/

View File

@ -79,7 +79,13 @@ HEADERS += \
$$PWD/qquickrendercontrol.h \
$$PWD/qquickrendercontrol_p.h \
$$PWD/qquickgraphicsinfo_p.h \
$$PWD/qquickitemgrabresult.h
$$PWD/qquickitemgrabresult.h \
$$PWD/qquickspriteengine_p.h \
$$PWD/qquicksprite_p.h \
$$PWD/qquickspritesequence_p.h \
$$PWD/qquickanimatedsprite_p.h \
$$PWD/qquickanimatedsprite_p_p.h \
$$PWD/qquickspritesequence_p_p.h
SOURCES += \
$$PWD/qquickevents.cpp \
@ -134,7 +140,11 @@ SOURCES += \
$$PWD/qquickgenericshadereffect.cpp \
$$PWD/qquickrendercontrol.cpp \
$$PWD/qquickgraphicsinfo.cpp \
$$PWD/qquickitemgrabresult.cpp
$$PWD/qquickitemgrabresult.cpp \
$$PWD/qquickspriteengine.cpp \
$$PWD/qquicksprite.cpp \
$$PWD/qquickspritesequence.cpp \
$$PWD/qquickanimatedsprite.cpp
# Items that depend on OpenGL Renderer
contains(QT_CONFIG, opengl(es1|es2)?) {
@ -142,31 +152,19 @@ contains(QT_CONFIG, opengl(es1|es2)?) {
$$PWD/qquickopenglinfo.cpp \
$$PWD/qquickopenglshadereffect.cpp \
$$PWD/qquickopenglshadereffectnode.cpp \
$$PWD/qquickframebufferobject.cpp \
$$PWD/qquickspriteengine.cpp \
$$PWD/qquicksprite.cpp \
$$PWD/qquickspritesequence.cpp \
$$PWD/qquickanimatedsprite.cpp
$$PWD/qquickframebufferobject.cpp
HEADERS += \
$$PWD/qquickopenglinfo_p.h \
$$PWD/qquickspriteengine_p.h \
$$PWD/qquicksprite_p.h \
$$PWD/qquickspritesequence_p.h \
$$PWD/qquickanimatedsprite_p.h \
$$PWD/qquickopenglshadereffect_p.h \
$$PWD/qquickopenglshadereffectnode_p.h \
$$PWD/qquickframebufferobject.h
OTHER_FILES += \
$$PWD/shaders/sprite.vert \
$$PWD/shaders/sprite.frag \
$$PWD/shaders/shadereffect.vert \
$$PWD/shaders/shadereffect.frag \
$$PWD/shaders/shadereffectfallback.vert \
$$PWD/shaders/shadereffectfallback.frag \
$$PWD/shaders/sprite_core.vert \
$$PWD/shaders/sprite_core.frag \
$$PWD/shaders/shadereffect_core.vert \
$$PWD/shaders/shadereffect_core.frag \
$$PWD/shaders/shadereffectfallback_core.vert \

View File

@ -1,7 +1,5 @@
<RCC>
<qresource prefix="/qt-project.org/items">
<file>shaders/sprite.frag</file>
<file>shaders/sprite.vert</file>
<file>shaders/shadereffect.vert</file>
<file>shaders/shadereffect.frag</file>
<file>shaders/shadereffectfallback.frag</file>
@ -10,7 +8,5 @@
<file>shaders/shadereffect_core.vert</file>
<file>shaders/shadereffectfallback_core.frag</file>
<file>shaders/shadereffectfallback_core.vert</file>
<file>shaders/sprite_core.frag</file>
<file>shaders/sprite_core.vert</file>
</qresource>
</RCC>

View File

@ -285,26 +285,26 @@ void QQuickAnchorsPrivate::clearItem(QQuickItem *item)
}
}
int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
QQuickGeometryChange QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
{
QQuickItemPrivate::GeometryChangeTypes dependency = QQuickItemPrivate::NoChange;
QQuickGeometryChange dependency;
if (!controlItem || inDestructor)
return dependency;
if (fill == controlItem) {
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::SizeChange;
dependency.setSizeChange(true);
else //sibling
dependency |= QQuickItemPrivate::GeometryChange;
dependency.setAllChanged(true);
return dependency; //exit early
}
if (centerIn == controlItem) {
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::SizeChange;
dependency.setSizeChange(true);
else //sibling
dependency |= QQuickItemPrivate::GeometryChange;
dependency.setAllChanged(true);
return dependency; //exit early
}
@ -312,9 +312,9 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
(usedAnchors & QQuickAnchors::RightAnchor && rightAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::HCenterAnchor && hCenterAnchorItem == controlItem)) {
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::WidthChange;
dependency.setWidthChange(true);
else //sibling
dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::XChange | QQuickItemPrivate::WidthChange);
dependency.setHorizontalChange(true);
}
if ((usedAnchors & QQuickAnchors::TopAnchor && topAnchorItem == controlItem) ||
@ -322,9 +322,9 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
(usedAnchors & QQuickAnchors::VCenterAnchor && vCenterAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::BaselineAnchor && baselineAnchorItem == controlItem)) {
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::HeightChange;
dependency.setHeightChange(true);
else //sibling
dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::YChange | QQuickItemPrivate::HeightChange);
dependency.setVerticalChange(true);
}
return dependency;
@ -336,7 +336,7 @@ void QQuickAnchorsPrivate::addDepend(QQuickItem *item)
return;
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
p->updateOrAddGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
p->updateOrAddGeometryChangeListener(this, calculateDependency(item));
}
void QQuickAnchorsPrivate::remDepend(QQuickItem *item)
@ -345,7 +345,7 @@ void QQuickAnchorsPrivate::remDepend(QQuickItem *item)
return;
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
p->updateOrRemoveGeometryChangeListener(this, QFlags<QQuickItemPrivate::GeometryChangeType>(calculateDependency(item)));
p->updateOrRemoveGeometryChangeListener(this, calculateDependency(item));
}
bool QQuickAnchors::mirrored()
@ -492,7 +492,7 @@ void QQuickAnchorsPrivate::update()
}
}
void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG, const QRectF &oldG)
void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &)
{
if (!isItemComplete())
return;
@ -502,11 +502,9 @@ void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG,
} else if (centerIn) {
centerInChanged();
} else {
if ((usedAnchors & QQuickAnchors::Horizontal_Mask)
&& (newG.x() != oldG.x() || newG.width() != oldG.width()))
if ((usedAnchors & QQuickAnchors::Horizontal_Mask) && change.horizontalChange())
updateHorizontalAnchors();
if ((usedAnchors & QQuickAnchors::Vertical_Mask)
&& (newG.y() != oldG.y() || newG.height() != oldG.height()))
if ((usedAnchors & QQuickAnchors::Vertical_Mask) && change.verticalChange())
updateVerticalAnchors();
}
}

View File

@ -124,7 +124,7 @@ public:
void clearItem(QQuickItem *);
int calculateDependency(QQuickItem *);
QQuickGeometryChange calculateDependency(QQuickItem *);
void addDepend(QQuickItem *);
void remDepend(QQuickItem *);
bool isItemComplete() const;
@ -141,7 +141,7 @@ public:
void updateMe();
// QQuickItemGeometryListener interface
void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
QQuickAnchorsPrivate *anchorPrivate() Q_DECL_OVERRIDE { return this; }
bool checkHValid() const;

View File

@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickanimatedsprite_p.h"
#include "qquickanimatedsprite_p_p.h"
#include "qquicksprite_p.h"
#include "qquickspriteengine_p.h"
#include <QtQuick/private/qsgcontext_p.h>
@ -55,111 +56,6 @@
QT_BEGIN_NAMESPACE
class QQuickAnimatedSpriteMaterial : public QSGMaterial
{
public:
QQuickAnimatedSpriteMaterial();
~QQuickAnimatedSpriteMaterial();
QSGMaterialType *type() const Q_DECL_OVERRIDE { static QSGMaterialType type; return &type; }
QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE
{
return this - static_cast<const QQuickAnimatedSpriteMaterial *>(other);
}
QSGTexture *texture;
float animT;
float animX1;
float animY1;
float animX2;
float animY2;
float animW;
float animH;
};
QQuickAnimatedSpriteMaterial::QQuickAnimatedSpriteMaterial()
: texture(0)
, animT(0.0f)
, animX1(0.0f)
, animY1(0.0f)
, animX2(0.0f)
, animY2(0.0f)
, animW(1.0f)
, animH(1.0f)
{
setFlag(Blending, true);
}
QQuickAnimatedSpriteMaterial::~QQuickAnimatedSpriteMaterial()
{
delete texture;
}
class AnimatedSpriteMaterialData : public QSGMaterialShader
{
public:
AnimatedSpriteMaterialData()
: QSGMaterialShader()
{
setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/sprite.vert"));
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/sprite.frag"));
}
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE
{
QQuickAnimatedSpriteMaterial *m = static_cast<QQuickAnimatedSpriteMaterial *>(newEffect);
m->texture->bind();
program()->setUniformValue(m_opacity_id, state.opacity());
program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT);
program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2);
if (state.isMatrixDirty())
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
}
void initialize() Q_DECL_OVERRIDE {
m_matrix_id = program()->uniformLocation("qt_Matrix");
m_opacity_id = program()->uniformLocation("qt_Opacity");
m_animData_id = program()->uniformLocation("animData");
m_animPos_id = program()->uniformLocation("animPos");
}
char const *const *attributeNames() const Q_DECL_OVERRIDE {
static const char *attr[] = {
"vPos",
"vTex",
0
};
return attr;
}
int m_matrix_id;
int m_opacity_id;
int m_animData_id;
int m_animPos_id;
};
QSGMaterialShader *QQuickAnimatedSpriteMaterial::createShader() const
{
return new AnimatedSpriteMaterialData;
}
struct AnimatedSpriteVertex {
float x;
float y;
float tx;
float ty;
};
struct AnimatedSpriteVertices {
AnimatedSpriteVertex v1;
AnimatedSpriteVertex v2;
AnimatedSpriteVertex v3;
AnimatedSpriteVertex v4;
};
/*!
\qmltype AnimatedSprite
\instantiates QQuickAnimatedSprite
@ -315,18 +211,11 @@ struct AnimatedSpriteVertices {
//TODO: Implicitly size element to size of sprite
QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
QQuickItem(parent)
, m_sprite(new QQuickSprite(this))
, m_spriteEngine(0)
, m_curFrame(0)
, m_pleaseReset(false)
, m_running(true)
, m_paused(false)
, m_interpolate(true)
, m_loops(-1)
, m_curLoop(0)
, m_pauseOffset(0)
QQuickItem(*(new QQuickAnimatedSpritePrivate), parent)
{
Q_D(QQuickAnimatedSprite);
d->m_sprite = new QQuickSprite(this);
setFlag(ItemHasContents);
connect(this, SIGNAL(widthChanged()),
this, SLOT(reset()));
@ -334,6 +223,96 @@ QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
this, SLOT(reset()));
}
bool QQuickAnimatedSprite::running() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_running;
}
bool QQuickAnimatedSprite::interpolate() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_interpolate;
}
QUrl QQuickAnimatedSprite::source() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->source();
}
bool QQuickAnimatedSprite::reverse() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->reverse();
}
bool QQuickAnimatedSprite::frameSync() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameSync();
}
int QQuickAnimatedSprite::frameCount() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frames();
}
int QQuickAnimatedSprite::frameHeight() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameHeight();
}
int QQuickAnimatedSprite::frameWidth() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameWidth();
}
int QQuickAnimatedSprite::frameX() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameX();
}
int QQuickAnimatedSprite::frameY() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameY();
}
qreal QQuickAnimatedSprite::frameRate() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameRate();
}
int QQuickAnimatedSprite::frameDuration() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_sprite->frameDuration();
}
int QQuickAnimatedSprite::loops() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_loops;
}
bool QQuickAnimatedSprite::paused() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_paused;
}
int QQuickAnimatedSprite::currentFrame() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_curFrame;
}
bool QQuickAnimatedSprite::isCurrentFrameChangedConnected()
{
IS_SIGNAL_CONNECTED(this, QQuickAnimatedSprite, currentFrameChanged, (int));
@ -348,23 +327,25 @@ void QQuickAnimatedSprite::reloadImage()
void QQuickAnimatedSprite::componentComplete()
{
Q_D(const QQuickAnimatedSprite);
createEngine();
QQuickItem::componentComplete();
if (m_running)
if (d->m_running)
start();
}
void QQuickAnimatedSprite::start()
{
m_running = true;
Q_D(QQuickAnimatedSprite);
d->m_running = true;
if (!isComponentComplete())
return;
m_curLoop = 0;
m_timestamp.start();
if (m_spriteEngine) {
m_spriteEngine->stop(0);
m_spriteEngine->updateSprites(0);
m_spriteEngine->start(0);
d->m_curLoop = 0;
d->m_timestamp.start();
if (d->m_spriteEngine) {
d->m_spriteEngine->stop(0);
d->m_spriteEngine->updateSprites(0);
d->m_spriteEngine->start(0);
}
emit currentFrameChanged(0);
emit runningChanged(true);
@ -373,10 +354,11 @@ void QQuickAnimatedSprite::start()
void QQuickAnimatedSprite::stop()
{
m_running = false;
Q_D(QQuickAnimatedSprite);
d->m_running = false;
if (!isComponentComplete())
return;
m_pauseOffset = 0;
d->m_pauseOffset = 0;
emit runningChanged(false);
update();
}
@ -388,14 +370,15 @@ void QQuickAnimatedSprite::stop()
*/
void QQuickAnimatedSprite::advance(int frames)
{
Q_D(QQuickAnimatedSprite);
if (!frames)
return;
//TODO-C: May not work when running - only when paused
m_curFrame += frames;
while (m_curFrame < 0)
m_curFrame += m_spriteEngine->maxFrames();
m_curFrame = m_curFrame % m_spriteEngine->maxFrames();
emit currentFrameChanged(m_curFrame);
d->m_curFrame += frames;
while (d->m_curFrame < 0)
d->m_curFrame += d->m_spriteEngine->maxFrames();
d->m_curFrame = d->m_curFrame % d->m_spriteEngine->maxFrames();
emit currentFrameChanged(d->m_curFrame);
update();
}
@ -409,10 +392,12 @@ void QQuickAnimatedSprite::advance(int frames)
*/
void QQuickAnimatedSprite::pause()
{
if (m_paused)
Q_D(QQuickAnimatedSprite);
if (d->m_paused)
return;
m_pauseOffset = m_timestamp.elapsed();
m_paused = true;
d->m_pauseOffset = d->m_timestamp.elapsed();
d->m_paused = true;
emit pausedChanged(true);
update();
}
@ -427,246 +412,363 @@ void QQuickAnimatedSprite::pause()
*/
void QQuickAnimatedSprite::resume()
{
if (!m_paused)
Q_D(QQuickAnimatedSprite);
if (!d->m_paused)
return;
m_pauseOffset = m_pauseOffset - m_timestamp.elapsed();
m_paused = false;
d->m_pauseOffset = d->m_pauseOffset - d->m_timestamp.elapsed();
d->m_paused = false;
emit pausedChanged(false);
update();
}
void QQuickAnimatedSprite::setRunning(bool arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_running != arg) {
if (d->m_running)
stop();
else
start();
}
}
void QQuickAnimatedSprite::setPaused(bool arg)
{
Q_D(const QQuickAnimatedSprite);
if (d->m_paused != arg) {
if (d->m_paused)
resume();
else
pause();
}
}
void QQuickAnimatedSprite::setInterpolate(bool arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_interpolate != arg) {
d->m_interpolate = arg;
Q_EMIT interpolateChanged(arg);
}
}
void QQuickAnimatedSprite::setSource(QUrl arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_source != arg) {
d->m_sprite->setSource(arg);
Q_EMIT sourceChanged(arg);
reloadImage();
}
}
void QQuickAnimatedSprite::setReverse(bool arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_reverse != arg) {
d->m_sprite->setReverse(arg);
Q_EMIT reverseChanged(arg);
}
}
void QQuickAnimatedSprite::setFrameSync(bool arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameSync != arg) {
d->m_sprite->setFrameSync(arg);
Q_EMIT frameSyncChanged(arg);
if (d->m_running)
restart();
}
}
void QQuickAnimatedSprite::setFrameCount(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frames != arg) {
d->m_sprite->setFrameCount(arg);
Q_EMIT frameCountChanged(arg);
reloadImage();
}
}
void QQuickAnimatedSprite::setFrameHeight(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameHeight != arg) {
d->m_sprite->setFrameHeight(arg);
Q_EMIT frameHeightChanged(arg);
reloadImage();
}
}
void QQuickAnimatedSprite::setFrameWidth(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameWidth != arg) {
d->m_sprite->setFrameWidth(arg);
Q_EMIT frameWidthChanged(arg);
reloadImage();
}
}
void QQuickAnimatedSprite::setFrameX(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameX != arg) {
d->m_sprite->setFrameX(arg);
Q_EMIT frameXChanged(arg);
reloadImage();
}
}
void QQuickAnimatedSprite::setFrameY(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameY != arg) {
d->m_sprite->setFrameY(arg);
Q_EMIT frameYChanged(arg);
reloadImage();
}
}
void QQuickAnimatedSprite::setFrameRate(qreal arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameRate != arg) {
d->m_sprite->setFrameRate(arg);
Q_EMIT frameRateChanged(arg);
if (d->m_running)
restart();
}
}
void QQuickAnimatedSprite::setFrameDuration(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_sprite->m_frameDuration != arg) {
d->m_sprite->setFrameDuration(arg);
Q_EMIT frameDurationChanged(arg);
if (d->m_running)
restart();
}
}
void QQuickAnimatedSprite::resetFrameRate()
{
setFrameRate(-1.0);
}
void QQuickAnimatedSprite::resetFrameDuration()
{
setFrameDuration(-1);
}
void QQuickAnimatedSprite::setLoops(int arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_loops != arg) {
d->m_loops = arg;
Q_EMIT loopsChanged(arg);
}
}
void QQuickAnimatedSprite::setCurrentFrame(int arg) //TODO-C: Probably only works when paused
{
Q_D(QQuickAnimatedSprite);
if (d->m_curFrame != arg) {
d->m_curFrame = arg;
Q_EMIT currentFrameChanged(arg); //TODO-C Only emitted on manual advance!
update();
}
}
void QQuickAnimatedSprite::createEngine()
{
if (m_spriteEngine)
delete m_spriteEngine;
Q_D(QQuickAnimatedSprite);
if (d->m_spriteEngine)
delete d->m_spriteEngine;
QList<QQuickSprite*> spriteList;
spriteList << m_sprite;
m_spriteEngine = new QQuickSpriteEngine(QList<QQuickSprite*>(spriteList), this);
m_spriteEngine->startAssemblingImage();
spriteList << d->m_sprite;
d->m_spriteEngine = new QQuickSpriteEngine(QList<QQuickSprite*>(spriteList), this);
d->m_spriteEngine->startAssemblingImage();
reset();
update();
}
static QSGGeometry::Attribute AnimatedSprite_Attributes[] = {
QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // pos
QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // tex
};
static QSGGeometry::AttributeSet AnimatedSprite_AttributeSet =
QSGSpriteNode* QQuickAnimatedSprite::initNode()
{
2, // Attribute Count
(2+2) * sizeof(float),
AnimatedSprite_Attributes
};
Q_D(QQuickAnimatedSprite);
void QQuickAnimatedSprite::sizeVertices(QSGGeometryNode *node)
{
AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) node->geometry()->vertexData();
p->v1.x = 0;
p->v1.y = 0;
p->v2.x = width();
p->v2.y = 0;
p->v3.x = 0;
p->v3.y = height();
p->v4.x = width();
p->v4.y = height();
}
QSGGeometryNode* QQuickAnimatedSprite::buildNode()
{
if (!m_spriteEngine) {
if (!d->m_spriteEngine) {
qmlInfo(this) << "No sprite engine...";
return 0;
} else if (m_spriteEngine->status() == QQuickPixmap::Null) {
m_spriteEngine->startAssemblingImage();
return nullptr;
} else if (d->m_spriteEngine->status() == QQuickPixmap::Null) {
d->m_spriteEngine->startAssemblingImage();
update();//Schedule another update, where we will check again
return 0;
} else if (m_spriteEngine->status() == QQuickPixmap::Loading) {
return nullptr;
} else if (d->m_spriteEngine->status() == QQuickPixmap::Loading) {
update();//Schedule another update, where we will check again
return 0;
return nullptr;
}
QQuickAnimatedSpriteMaterial *material = new QQuickAnimatedSpriteMaterial();
QImage image = m_spriteEngine->assembledImage(); //Engine prints errors if there are any
QImage image = d->m_spriteEngine->assembledImage(d->sceneGraphRenderContext()->maxTextureSize()); //Engine prints errors if there are any
if (image.isNull())
return 0;
m_sheetSize = QSizeF(image.size());
material->texture = window()->createTextureFromImage(image);
m_spriteEngine->start(0);
material->animT = 0;
material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width();
material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height();
material->animX2 = material->animX1;
material->animY2 = material->animY1;
material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width();
material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height();
return nullptr;
int vCount = 4;
int iCount = 6;
QSGGeometry *g = new QSGGeometry(AnimatedSprite_AttributeSet, vCount, iCount);
g->setDrawingMode(GL_TRIANGLES);
QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode();
AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) g->vertexData();
QRectF texRect = material->texture->normalizedTextureSubRect();
p->v1.tx = texRect.topLeft().x();
p->v1.ty = texRect.topLeft().y();
p->v2.tx = texRect.topRight().x();
p->v2.ty = texRect.topRight().y();
p->v3.tx = texRect.bottomLeft().x();
p->v3.ty = texRect.bottomLeft().y();
p->v4.tx = texRect.bottomRight().x();
p->v4.ty = texRect.bottomRight().y();
quint16 *indices = g->indexDataAsUShort();
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 1;
indices[4] = 3;
indices[5] = 2;
QSGGeometryNode *node = new QSGGeometryNode();
node->setGeometry(g);
node->setMaterial(material);
node->setFlag(QSGGeometryNode::OwnsMaterial);
node->setFlag(QSGGeometryNode::OwnsGeometry);
sizeVertices(node);
d->m_sheetSize = QSize(image.size());
node->setTexture(window()->createTextureFromImage(image));
d->m_spriteEngine->start(0);
node->setTime(0.0f);
node->setSourceA(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY()));
node->setSourceB(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY()));
node->setSpriteSize(QSize(d->m_spriteEngine->spriteWidth(), d->m_spriteEngine->spriteHeight()));
node->setSheetSize(d->m_sheetSize);
node->setSize(QSizeF(width(), height()));
return node;
}
void QQuickAnimatedSprite::reset()
{
m_pleaseReset = true;
Q_D(QQuickAnimatedSprite);
d->m_pleaseReset = true;
update();
}
QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
if (m_pleaseReset) {
Q_D(QQuickAnimatedSprite);
if (d->m_pleaseReset) {
delete oldNode;
oldNode = 0;
m_pleaseReset = false;
oldNode = nullptr;
d->m_pleaseReset = false;
}
QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
QSGSpriteNode *node = static_cast<QSGSpriteNode *>(oldNode);
if (!node)
node = buildNode();
node = initNode();
if (node)
prepareNextFrame(node);
if (m_running) {
if (!m_paused)
update();
if (node) {
node->markDirty(QSGNode::DirtyMaterial);
}
}
if (d->m_running && !d->m_paused)
update();
return node;
}
void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node)
void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
{
int timeInt = m_timestamp.elapsed() + m_pauseOffset;
Q_D(QQuickAnimatedSprite);
int timeInt = d->m_timestamp.elapsed() + d->m_pauseOffset;
qreal time = timeInt / 1000.;
int frameAt;
qreal progress = 0.0;
int lastFrame = m_curFrame;
if (m_running && !m_paused) {
const int nColumns = int(m_sheetSize.width()) / m_spriteEngine->spriteWidth();
int lastFrame = d->m_curFrame;
if (d->m_running && !d->m_paused) {
const int nColumns = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth();
//Advance State (keeps time for psuedostates)
m_spriteEngine->updateSprites(timeInt);
d->m_spriteEngine->updateSprites(timeInt);
//Advance AnimatedSprite
qreal animT = m_spriteEngine->spriteStart()/1000.0;
const int frameCountInRow = m_spriteEngine->spriteFrames();
const qreal frameDuration = m_spriteEngine->spriteDuration()/frameCountInRow;
qreal animT = d->m_spriteEngine->spriteStart()/1000.0;
const int frameCountInRow = d->m_spriteEngine->spriteFrames();
const qreal frameDuration = d->m_spriteEngine->spriteDuration() / frameCountInRow;
if (frameDuration > 0) {
qreal frame = (time - animT)/(frameDuration / 1000.0);
bool lastLoop = m_loops > 0 && m_curLoop == m_loops-1;
bool lastLoop = d->m_loops > 0 && d->m_curLoop == d->m_loops-1;
//don't visually interpolate for the last frame of the last loop
const int max = lastLoop ? frameCountInRow - 1 : frameCountInRow;
frame = qBound(qreal(0.0), frame, qreal(max));
double intpart;
progress = std::modf(frame,&intpart);
frameAt = (int)intpart;
const int rowIndex = m_spriteEngine->spriteY()/frameHeight();
const int rowIndex = d->m_spriteEngine->spriteY()/frameHeight();
const int newFrame = rowIndex * nColumns + frameAt;
if (m_curFrame > newFrame) //went around
m_curLoop++;
m_curFrame = newFrame;
if (d->m_curFrame > newFrame) //went around
d->m_curLoop++;
d->m_curFrame = newFrame;
} else {
m_curFrame++;
if (m_curFrame >= m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows
m_curFrame = 0;
m_curLoop++;
d->m_curFrame++;
if (d->m_curFrame >= d->m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows
d->m_curFrame = 0;
d->m_curLoop++;
}
frameAt = m_curFrame % nColumns;
frameAt = d->m_curFrame % nColumns;
if (frameAt == 0)
m_spriteEngine->advance();
d->m_spriteEngine->advance();
progress = 0;
}
if (m_loops > 0 && m_curLoop >= m_loops) {
if (d->m_loops > 0 && d->m_curLoop >= d->m_loops) {
frameAt = 0;
m_running = false;
d->m_running = false;
emit runningChanged(false);
update();
}
} else {
frameAt = m_curFrame;
frameAt = d->m_curFrame;
}
if (m_curFrame != lastFrame) {
if (d->m_curFrame != lastFrame) {
if (isCurrentFrameChangedConnected())
emit currentFrameChanged(m_curFrame);
emit currentFrameChanged(d->m_curFrame);
update();
}
qreal frameCount = m_spriteEngine->spriteFrames();
bool reverse = m_spriteEngine->sprite()->reverse();
qreal frameCount = d->m_spriteEngine->spriteFrames();
bool reverse = d->m_spriteEngine->sprite()->reverse();
if (reverse)
frameAt = (frameCount - 1) - frameAt;
qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width();
qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height();
qreal x1;
qreal y1;
if (m_paused) {
int spriteY = m_spriteEngine->spriteY();
int w = d->m_spriteEngine->spriteWidth();
int h = d->m_spriteEngine->spriteHeight();
int x1;
int y1;
if (d->m_paused) {
int spriteY = d->m_spriteEngine->spriteY();
if (reverse) {
int rows = m_spriteEngine->maxFrames() * m_spriteEngine->spriteWidth() / m_sheetSize.width();
spriteY -= rows * m_spriteEngine->spriteHeight();
int rows = d->m_spriteEngine->maxFrames() * d->m_spriteEngine->spriteWidth() / d->m_sheetSize.width();
spriteY -= rows * d->m_spriteEngine->spriteHeight();
frameAt = (frameCount - 1) - frameAt;
}
int position = frameAt * m_spriteEngine->spriteWidth() + m_spriteEngine->spriteX();
int row = position / m_sheetSize.width();
int position = frameAt * d->m_spriteEngine->spriteWidth() + d->m_spriteEngine->spriteX();
int row = position / d->m_sheetSize.width();
x1 = (position - (row * m_sheetSize.width())) / m_sheetSize.width();
y1 = (row * m_spriteEngine->spriteHeight() + spriteY) / m_sheetSize.height();
x1 = (position - (row * d->m_sheetSize.width()));
y1 = (row * d->m_spriteEngine->spriteHeight() + spriteY);
} else {
x1 = m_spriteEngine->spriteX() / m_sheetSize.width() + frameAt * w;
y1 = m_spriteEngine->spriteY() / m_sheetSize.height();
x1 = d->m_spriteEngine->spriteX() + frameAt * w;
y1 = d->m_spriteEngine->spriteY();
}
//### hard-coded 0/1 work because we are the only
// images in the sprite sheet (without this we cannot assume
// where in the sheet we begin/end).
qreal x2;
qreal y2;
int x2;
int y2;
if (reverse) {
if (frameAt > 0) {
x2 = x1 - w;
@ -676,9 +778,9 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node)
y2 = y1 - h;
if (y2 < 0.0) {
//the last row may not fill the entire width
int maxRowFrames = m_sheetSize.width() / m_spriteEngine->spriteWidth();
if (m_spriteEngine->maxFrames() % maxRowFrames)
x2 = ((m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w;
int maxRowFrames = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth();
if (d->m_spriteEngine->maxFrames() % maxRowFrames)
x2 = ((d->m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w;
y2 = 1.0 - h;
}
@ -695,15 +797,13 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node)
}
}
QQuickAnimatedSpriteMaterial *material = static_cast<QQuickAnimatedSpriteMaterial *>(node->material());
material->animX1 = x1;
material->animY1 = y1;
material->animX2 = x2;
material->animY2 = y2;
material->animW = w;
material->animH = h;
material->animT = m_interpolate ? progress : 0.0;
material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
node->setSourceA(QPoint(x1, y1));
node->setSourceB(QPoint(x2, y2));
node->setSpriteSize(QSize(w, h));
node->setTime(d->m_interpolate ? progress : 0.0);
node->setSize(QSizeF(width(), height()));
node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
node->update();
}
QT_END_NAMESPACE

View File

@ -62,6 +62,8 @@ class QQuickSprite;
class QQuickSpriteEngine;
class QSGGeometryNode;
class QQuickAnimatedSpriteMaterial;
class QQuickAnimatedSpritePrivate;
class QSGSpriteNode;
class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem
{
Q_OBJECT
@ -94,80 +96,21 @@ public:
};
Q_ENUM(LoopParameters)
bool running() const
{
return m_running;
}
bool interpolate() const
{
return m_interpolate;
}
QUrl source() const
{
return m_sprite->source();
}
bool reverse() const
{
return m_sprite->reverse();
}
bool frameSync() const
{
return m_sprite->frameSync();
}
int frameCount() const
{
return m_sprite->frames();
}
int frameHeight() const
{
return m_sprite->frameHeight();
}
int frameWidth() const
{
return m_sprite->frameWidth();
}
int frameX() const
{
return m_sprite->frameX();
}
int frameY() const
{
return m_sprite->frameY();
}
qreal frameRate() const
{
return m_sprite->frameRate();
}
int frameDuration() const
{
return m_sprite->frameDuration();
}
int loops() const
{
return m_loops;
}
bool paused() const
{
return m_paused;
}
int currentFrame() const
{
return m_curFrame;
}
bool running() const;
bool interpolate() const;
QUrl source() const;
bool reverse() const;
bool frameSync() const;
int frameCount() const;
int frameHeight() const;
int frameWidth() const;
int frameX() const;
int frameY() const;
qreal frameRate() const;
int frameDuration() const;
int loops() const;
bool paused() const;
int currentFrame() const;
Q_SIGNALS:
@ -176,27 +119,16 @@ Q_SIGNALS:
void interpolateChanged(bool arg);
void sourceChanged(QUrl arg);
void reverseChanged(bool arg);
void frameSyncChanged(bool arg);
void frameCountChanged(int arg);
void frameHeightChanged(int arg);
void frameWidthChanged(int arg);
void frameXChanged(int arg);
void frameYChanged(int arg);
void frameRateChanged(qreal arg);
void frameDurationChanged(int arg);
void loopsChanged(int arg);
void currentFrameChanged(int arg);
public Q_SLOTS:
@ -207,157 +139,27 @@ public Q_SLOTS:
void pause();
void resume();
void setRunning(bool arg)
{
if (m_running != arg) {
if (m_running)
stop();
else
start();
}
}
void setPaused(bool arg)
{
if (m_paused != arg) {
if (m_paused)
resume();
else
pause();
}
}
void setInterpolate(bool arg)
{
if (m_interpolate != arg) {
m_interpolate = arg;
Q_EMIT interpolateChanged(arg);
}
}
void setSource(QUrl arg)
{
if (m_sprite->m_source != arg) {
m_sprite->setSource(arg);
Q_EMIT sourceChanged(arg);
reloadImage();
}
}
void setReverse(bool arg)
{
if (m_sprite->m_reverse != arg) {
m_sprite->setReverse(arg);
Q_EMIT reverseChanged(arg);
}
}
void setFrameSync(bool arg)
{
if (m_sprite->m_frameSync != arg) {
m_sprite->setFrameSync(arg);
Q_EMIT frameSyncChanged(arg);
if (m_running)
restart();
}
}
void setFrameCount(int arg)
{
if (m_sprite->m_frames != arg) {
m_sprite->setFrameCount(arg);
Q_EMIT frameCountChanged(arg);
reloadImage();
}
}
void setFrameHeight(int arg)
{
if (m_sprite->m_frameHeight != arg) {
m_sprite->setFrameHeight(arg);
Q_EMIT frameHeightChanged(arg);
reloadImage();
}
}
void setFrameWidth(int arg)
{
if (m_sprite->m_frameWidth != arg) {
m_sprite->setFrameWidth(arg);
Q_EMIT frameWidthChanged(arg);
reloadImage();
}
}
void setFrameX(int arg)
{
if (m_sprite->m_frameX != arg) {
m_sprite->setFrameX(arg);
Q_EMIT frameXChanged(arg);
reloadImage();
}
}
void setFrameY(int arg)
{
if (m_sprite->m_frameY != arg) {
m_sprite->setFrameY(arg);
Q_EMIT frameYChanged(arg);
reloadImage();
}
}
void setFrameRate(qreal arg)
{
if (m_sprite->m_frameRate != arg) {
m_sprite->setFrameRate(arg);
Q_EMIT frameRateChanged(arg);
if (m_running)
restart();
}
}
void setFrameDuration(int arg)
{
if (m_sprite->m_frameDuration != arg) {
m_sprite->setFrameDuration(arg);
Q_EMIT frameDurationChanged(arg);
if (m_running)
restart();
}
}
void resetFrameRate()
{
setFrameRate(-1.0);
}
void resetFrameDuration()
{
setFrameDuration(-1);
}
void setLoops(int arg)
{
if (m_loops != arg) {
m_loops = arg;
Q_EMIT loopsChanged(arg);
}
}
void setCurrentFrame(int arg) //TODO-C: Probably only works when paused
{
if (m_curFrame != arg) {
m_curFrame = arg;
Q_EMIT currentFrameChanged(arg); //TODO-C Only emitted on manual advance!
update();
}
}
void setRunning(bool arg);
void setPaused(bool arg);
void setInterpolate(bool arg);
void setSource(QUrl arg);
void setReverse(bool arg);
void setFrameSync(bool arg);
void setFrameCount(int arg);
void setFrameHeight(int arg);
void setFrameWidth(int arg);
void setFrameX(int arg);
void setFrameY(int arg);
void setFrameRate(qreal arg);
void setFrameDuration(int arg);
void resetFrameRate();
void resetFrameDuration();
void setLoops(int arg);
void setCurrentFrame(int arg);
private Q_SLOTS:
void createEngine();
void sizeVertices(QSGGeometryNode *node);
protected Q_SLOTS:
void reset();
@ -367,21 +169,13 @@ protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
private:
bool isCurrentFrameChangedConnected();
void prepareNextFrame(QSGGeometryNode *node);
void prepareNextFrame(QSGSpriteNode *node);
void reloadImage();
QSGGeometryNode* buildNode();
QQuickSprite* m_sprite;
QQuickSpriteEngine* m_spriteEngine;
QElapsedTimer m_timestamp;
int m_curFrame;
bool m_pleaseReset;
bool m_running;
bool m_paused;
bool m_interpolate;
QSizeF m_sheetSize;
int m_loops;
int m_curLoop;
int m_pauseOffset;
QSGSpriteNode* initNode();
private:
Q_DISABLE_COPY(QQuickAnimatedSprite)
Q_DECLARE_PRIVATE(QQuickAnimatedSprite)
};
QT_END_NAMESPACE

View File

@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QQUICKANIMATEDSPRITE_P_P_H
#define QQUICKANIMATEDSPRITE_P_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 "qquickitem_p.h"
#include "qquicksprite_p.h"
QT_BEGIN_NAMESPACE
class QQuickAnimatedSprite;
class QQuickAnimatedSpritePrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickAnimatedSprite)
public:
QQuickAnimatedSpritePrivate()
: m_sprite(nullptr)
, m_spriteEngine(nullptr)
, m_curFrame(0)
, m_pleaseReset(false)
, m_running(true)
, m_paused(false)
, m_interpolate(true)
, m_loops(-1)
, m_curLoop(0)
, m_pauseOffset(0)
{
}
QQuickSprite* m_sprite;
QQuickSpriteEngine* m_spriteEngine;
QElapsedTimer m_timestamp;
int m_curFrame;
bool m_pleaseReset;
bool m_running;
bool m_paused;
bool m_interpolate;
QSize m_sheetSize;
int m_loops;
int m_curLoop;
int m_pauseOffset;
};
QT_END_NAMESPACE
#endif // QQUICKANIMATEDSPRITE_P_P_H

View File

@ -82,7 +82,7 @@ public:
{
}
void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
void itemParentChanged(QQuickItem *, QQuickItem *parent) Q_DECL_OVERRIDE;
void updatePosition();
void restartDrag();
@ -148,9 +148,10 @@ public:
\sa {Qt Quick Examples - Drag and Drop}, {Qt Quick Examples - externaldraganddrop}
*/
void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change,
const QRectF &)
{
if (newGeometry.topLeft() == oldGeometry.topLeft() || !active || itemMoved)
if (!change.positionChange() || !active || itemMoved)
return;
updatePosition();
}

View File

@ -222,6 +222,22 @@ private:
bool _accepted;
};
class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
{
Q_OBJECT
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
QQuickCloseEvent()
: _accepted(true) {}
bool isAccepted() { return _accepted; }
void setAccepted(bool accepted) { _accepted = accepted; }
private:
bool _accepted;
};
class Q_QUICK_PRIVATE_EXPORT QQuickEventPoint : public QObject
{
Q_OBJECT
@ -461,6 +477,7 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickKeyEvent)
QML_DECLARE_TYPE(QQuickMouseEvent)
QML_DECLARE_TYPE(QQuickWheelEvent)
QML_DECLARE_TYPE(QQuickCloseEvent)
QML_DECLARE_TYPE(QQuickPointerDevice)
QML_DECLARE_TYPE(QPointerUniqueId)
QML_DECLARE_TYPE(QQuickPointerEvent)

View File

@ -292,14 +292,14 @@ void QQuickFlickablePrivate::AxisData::updateVelocity()
}
}
void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeom, const QRectF &oldGeom)
void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
Qt::Orientations orient = 0;
if (newGeom.x() != oldGeom.x())
if (change.xChange())
orient |= Qt::Horizontal;
if (newGeom.y() != oldGeom.y())
if (change.yChange())
orient |= Qt::Vertical;
if (orient)
q->viewportMoved(orient);

View File

@ -194,7 +194,7 @@ public:
qreal overShootDistance(qreal size);
void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
void draggingStarting();
void draggingEnding();

View File

@ -305,8 +305,16 @@ void QQuickGenericShaderEffect::maybeUpdateShaders()
m_vertNeedsUpdate = !updateShader(Vertex, m_vertShader);
if (m_fragNeedsUpdate)
m_fragNeedsUpdate = !updateShader(Fragment, m_fragShader);
if (m_vertNeedsUpdate || m_fragNeedsUpdate)
m_item->polish();
if (m_vertNeedsUpdate || m_fragNeedsUpdate) {
// This function is invoked either from componentComplete or in a
// response to a previous invocation's polish() request. If this is
// case #1 then updateShader can fail due to not having a window or
// scenegraph ready. Schedule the polish to try again later. In case #2
// the backend probably does not have shadereffect support so there is
// nothing to do for us here.
if (!m_item->window() || !m_item->window()->isSceneGraphInitialized())
m_item->polish();
}
}
void QQuickGenericShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)

View File

@ -42,6 +42,19 @@
QT_BEGIN_NAMESPACE
/*!
\internal
The purpose of QQuickImplicitSizeItem is not immediately clear, as both
the implicit size properties and signals exist on QQuickItem. However,
for some items - where the implicit size has an underlying meaning (such as
Image, where the implicit size represents the real size of the image)
having implicit size writable is an undesirable thing.
QQuickImplicitSizeItem redefines the properties as being readonly.
Unfortunately, this also means they need to redefine the change signals.
See QTBUG-30258 for more information.
*/
void QQuickImplicitSizeItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickImplicitSizeItem);

View File

@ -88,10 +88,6 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET)
Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
#ifndef QT_NO_DEBUG
static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
#endif
void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
{
if (DBG_FOCUS().isEnabled(QtDebugMsg)) {
@ -102,7 +98,7 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
<< item->hasActiveFocus()
<< item->isFocusScope()
<< item;
foreach (QQuickItem *child, item->childItems()) {
for (QQuickItem *child : item->childItems()) {
debugFocusTree(
child,
item->isFocusScope() || !scope ? item : scope,
@ -117,17 +113,17 @@ static void QQuickItem_parentNotifier(QObject *o, QQmlNotifier **n)
*n = &d->parentNotifier;
}
QML_PRIVATE_ACCESSOR(QQuickItem, QQuickItem *, parent, parentItem)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, x, x)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, y, y)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, width, width)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, height, height)
QML_PRIVATE_ACCESSOR(QQuickItem, QQuickItem *, parent, parentItem, setParentItem)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, x, x, setX)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, y, y, setY)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, width, width, setWidth)
QML_PRIVATE_ACCESSOR(QQuickItem, qreal, height, height, setHeight)
static QQmlAccessors QQuickItem_parent = { QQuickItem_parentRead, QQuickItem_parentNotifier };
static QQmlAccessors QQuickItem_x = { QQuickItem_xRead, 0 };
static QQmlAccessors QQuickItem_y = { QQuickItem_yRead, 0 };
static QQmlAccessors QQuickItem_width = { QQuickItem_widthRead, 0 };
static QQmlAccessors QQuickItem_height = { QQuickItem_heightRead, 0 };
static QQmlAccessors QQuickItem_parent = { QQuickItem_parentRead, QQuickItem_parentWrite, QQuickItem_parentNotifier };
static QQmlAccessors QQuickItem_x = { QQuickItem_xRead, QQuickItem_xWrite, 0 };
static QQmlAccessors QQuickItem_y = { QQuickItem_yRead, QQuickItem_yWrite, 0 };
static QQmlAccessors QQuickItem_width = { QQuickItem_widthRead, QQuickItem_widthWrite, 0 };
static QQmlAccessors QQuickItem_height = { QQuickItem_heightRead, QQuickItem_heightWrite, 0 };
QML_DECLARE_PROPERTIES(QQuickItem) {
{ QML_PROPERTY_NAME(parent), 0, &QQuickItem_parent },
@ -181,8 +177,8 @@ QQuickTransform::QQuickTransform(QQuickTransformPrivate &dd, QObject *parent)
QQuickTransform::~QQuickTransform()
{
Q_D(QQuickTransform);
for (int ii = 0; ii < d->items.count(); ++ii) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->items.at(ii));
for (QQuickItem *item : qAsConst(d->items)) {
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
p->transforms.removeOne(this);
p->dirty(QQuickItemPrivate::Transform);
}
@ -191,8 +187,8 @@ QQuickTransform::~QQuickTransform()
void QQuickTransform::update()
{
Q_D(QQuickTransform);
for (int ii = 0; ii < d->items.count(); ++ii) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->items.at(ii));
for (QQuickItem *item : qAsConst(d->items)) {
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
p->dirty(QQuickItemPrivate::Transform);
}
}
@ -204,9 +200,7 @@ QQuickContents::QQuickContents(QQuickItem *item)
QQuickContents::~QQuickContents()
{
QList<QQuickItem *> children = m_item->childItems();
for (int i = 0; i < children.count(); ++i) {
QQuickItem *child = children.at(i);
for (QQuickItem *child : m_item->childItems()) {
QQuickItemPrivate::get(child)->removeItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
}
}
@ -229,9 +223,8 @@ bool QQuickContents::calcHeight(QQuickItem *changed)
} else {
qreal top = std::numeric_limits<qreal>::max();
qreal bottom = -std::numeric_limits<qreal>::max();
QList<QQuickItem *> children = m_item->childItems();
for (int i = 0; i < children.count(); ++i) {
QQuickItem *child = children.at(i);
const QList<QQuickItem*> children = m_item->childItems();
for (QQuickItem *child : qAsConst(children)) {
qreal y = child->y();
if (y + child->height() > bottom)
bottom = y + child->height();
@ -264,9 +257,8 @@ bool QQuickContents::calcWidth(QQuickItem *changed)
} else {
qreal left = std::numeric_limits<qreal>::max();
qreal right = -std::numeric_limits<qreal>::max();
QList<QQuickItem *> children = m_item->childItems();
for (int i = 0; i < children.count(); ++i) {
QQuickItem *child = children.at(i);
const QList<QQuickItem*> children = m_item->childItems();
for (QQuickItem *child : qAsConst(children)) {
qreal x = child->x();
if (x + child->width() > right)
right = x + child->width();
@ -285,9 +277,7 @@ void QQuickContents::complete()
{
QQuickItemPrivate::get(m_item)->addItemChangeListener(this, QQuickItemPrivate::Children);
QList<QQuickItem *> children = m_item->childItems();
for (int i = 0; i < children.count(); ++i) {
QQuickItem *child = children.at(i);
for (QQuickItem *child : m_item->childItems()) {
QQuickItemPrivate::get(child)->addItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
//###what about changes to visibility?
}
@ -299,15 +289,15 @@ void QQuickContents::updateRect()
QQuickItemPrivate::get(m_item)->emitChildrenRectChanged(rectF());
}
void QQuickContents::itemGeometryChanged(QQuickItem *changed, const QRectF &newGeometry, const QRectF &oldGeometry)
void QQuickContents::itemGeometryChanged(QQuickItem *changed, QQuickGeometryChange change, const QRectF &)
{
Q_UNUSED(changed)
bool wChanged = false;
bool hChanged = false;
//### we can only pass changed if the left edge has moved left, or the right edge has moved right
if (newGeometry.width() != oldGeometry.width() || newGeometry.x() != oldGeometry.x())
if (change.horizontalChange())
wChanged = calcWidth(/*changed*/);
if (newGeometry.height() != oldGeometry.height() || newGeometry.y() != oldGeometry.y())
if (change.verticalChange())
hChanged = calcHeight(/*changed*/);
if (wChanged || hChanged)
updateRect();
@ -1342,8 +1332,7 @@ void QQuickKeysAttached::componentComplete()
#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);
for (QQuickItem *targetItem : qAsConst(d->targets)) {
if (targetItem && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod)) {
d->item->setFlag(QQuickItem::ItemAcceptsInputMethod);
break;
@ -1365,11 +1354,10 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post)
// first process forwards
if (d->item && d->item->window()) {
d->inPress = true;
for (int ii = 0; ii < d->targets.count(); ++ii) {
QQuickItem *i = d->targets.at(ii);
if (i && i->isVisible()) {
for (QQuickItem *targetItem : qAsConst(d->targets)) {
if (targetItem && targetItem->isVisible()) {
event->accept();
QCoreApplication::sendEvent(i, event);
QCoreApplication::sendEvent(targetItem, event);
if (event->isAccepted()) {
d->inPress = false;
return;
@ -1409,11 +1397,10 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post)
if (d->item && d->item->window()) {
d->inRelease = true;
for (int ii = 0; ii < d->targets.count(); ++ii) {
QQuickItem *i = d->targets.at(ii);
if (i && i->isVisible()) {
for (QQuickItem *targetItem : qAsConst(d->targets)) {
if (targetItem && targetItem->isVisible()) {
event->accept();
QCoreApplication::sendEvent(i, event);
QCoreApplication::sendEvent(targetItem, event);
if (event->isAccepted()) {
d->inRelease = false;
return;
@ -1437,12 +1424,11 @@ void QQuickKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool post)
Q_D(QQuickKeysAttached);
if (post == m_processPost && d->item && !d->inIM && d->item->window()) {
d->inIM = true;
for (int ii = 0; ii < d->targets.count(); ++ii) {
QQuickItem *i = d->targets.at(ii);
if (i && i->isVisible() && (i->flags() & QQuickItem::ItemAcceptsInputMethod)) {
d->item->window()->sendEvent(i, event);
for (QQuickItem *targetItem : qAsConst(d->targets)) {
if (targetItem && targetItem->isVisible() && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod)) {
d->item->window()->sendEvent(targetItem, event);
if (event->isAccepted()) {
d->imeItem = i;
d->imeItem = targetItem;
d->inIM = false;
return;
}
@ -1457,13 +1443,12 @@ QVariant QQuickKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const
{
Q_D(const QQuickKeysAttached);
if (d->item) {
for (int ii = 0; ii < d->targets.count(); ++ii) {
QQuickItem *i = d->targets.at(ii);
if (i && i->isVisible() && (i->flags() & QQuickItem::ItemAcceptsInputMethod) && i == d->imeItem) {
//### how robust is i == d->imeItem check?
QVariant v = i->inputMethodQuery(query);
for (QQuickItem *targetItem : qAsConst(d->targets)) {
if (targetItem && targetItem->isVisible() && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod) && targetItem == d->imeItem) {
//### how robust is targetItem == d->imeItem check?
QVariant v = targetItem->inputMethodQuery(query);
if (v.userType() == QVariant::RectF)
v = d->item->mapRectFromItem(i, v.toRectF()); //### cost?
v = d->item->mapRectFromItem(targetItem, v.toRectF()); //### cost?
return v;
}
}
@ -1620,11 +1605,9 @@ void QQuickItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit)
if (isMirrorImplicit)
setLayoutMirror(inherit ? inheritedLayoutMirror : false);
for (int i = 0; i < childItems.count(); ++i) {
if (QQuickItem *child = qmlobject_cast<QQuickItem *>(childItems.at(i))) {
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
}
for (QQuickItem *child : qAsConst(childItems)) {
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
}
}
@ -2328,29 +2311,11 @@ QQuickItem::QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent)
d->init(parent);
}
#ifndef QT_NO_DEBUG
static int qt_item_count = 0;
static void qt_print_item_count()
{
qDebug("Number of leaked items: %i", qt_item_count);
qt_item_count = -1;
}
#endif
/*!
Destroys the QQuickItem.
*/
QQuickItem::~QQuickItem()
{
#ifndef QT_NO_DEBUG
if (qsg_leak_check) {
--qt_item_count;
if (qt_item_count < 0)
qDebug("Item destroyed after qt_print_item_count() was called.");
}
#endif
Q_D(QQuickItem);
if (d->windowRefCount > 1)
@ -2364,7 +2329,7 @@ QQuickItem::~QQuickItem()
while (!d->childItems.isEmpty())
d->childItems.constFirst()->setParentItem(0);
const auto listeners = d->changeListeners;
const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor)
@ -2393,8 +2358,7 @@ QQuickItem::~QQuickItem()
remove themselves from our list of transforms when that list has already
been destroyed after ~QQuickItem() has run.
*/
for (int ii = 0; ii < d->transforms.count(); ++ii) {
QQuickTransform *t = d->transforms.at(ii);
for (QQuickTransform *t : qAsConst(d->transforms)) {
QQuickTransformPrivate *tp = QQuickTransformPrivate::get(t);
tp->items.removeOne(this);
}
@ -2885,8 +2849,8 @@ QList<QQuickItem *> QQuickItemPrivate::paintOrderChildItems() const
// If none of the items have set Z then the paint order list is the same as
// the childItems list. This is by far the most common case.
bool haveZ = false;
for (int i = 0; i < childItems.count(); ++i) {
if (QQuickItemPrivate::get(childItems.at(i))->z() != 0.) {
for (QQuickItem *childItem : qAsConst(childItems)) {
if (QQuickItemPrivate::get(childItem)->z() != 0.) {
haveZ = true;
break;
}
@ -2915,7 +2879,7 @@ void QQuickItemPrivate::addChild(QQuickItem *child)
// if the added child has a cursor and we do not currently have any children
// with cursors, bubble the notification up
if (childPrivate->hasCursorInChild && !hasCursorInChild)
if (childPrivate->subtreeCursorEnabled && !subtreeCursorEnabled)
setHasCursorInChild(true);
#endif
if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled)
@ -2942,7 +2906,7 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
// turn it off, if nothing else is using it
if (childPrivate->hasCursorInChild && hasCursorInChild)
if (childPrivate->subtreeCursorEnabled && subtreeCursorEnabled)
setHasCursorInChild(false);
#endif
if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled)
@ -2985,8 +2949,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
if (!parentItem)
QQuickWindowPrivate::get(window)->parentlessItems.insert(q);
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItem *child = childItems.at(ii);
for (QQuickItem *child : qAsConst(childItems)) {
QQuickItemPrivate::get(child)->refWindow(c);
}
@ -3038,8 +3001,7 @@ void QQuickItemPrivate::derefWindow()
paintNode = 0;
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItem *child = childItems.at(ii);
for (QQuickItem *child : qAsConst(childItems)) {
QQuickItemPrivate::get(child)->derefWindow();
}
@ -3162,7 +3124,7 @@ QQuickItemPrivate::QQuickItemPrivate()
, isAccessible(false)
, culled(false)
, hasCursor(false)
, hasCursorInChild(false)
, subtreeCursorEnabled(false)
, subtreeHoverEnabled(false)
, activeFocusOnTab(false)
, implicitAntialiasing(false)
@ -3197,17 +3159,6 @@ QQuickItemPrivate::~QQuickItemPrivate()
void QQuickItemPrivate::init(QQuickItem *parent)
{
#ifndef QT_NO_DEBUG
if (qsg_leak_check) {
++qt_item_count;
static bool atexit_registered = false;
if (!atexit_registered) {
atexit(qt_print_item_count);
atexit_registered = true;
}
}
#endif
Q_Q(QQuickItem);
registerAccessorProperties();
@ -3356,7 +3307,7 @@ void QQuickItemPrivate::resources_clear(QQmlListProperty<QObject> *prop)
QQuickItem *quickItem = static_cast<QQuickItem *>(prop->object);
QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(quickItem);
if (quickItemPrivate->extra.isAllocated()) {//If extra is not allocated resources is empty.
foreach (QObject *object, quickItemPrivate->extra->resourcesList) {
for (QObject *object : qAsConst(quickItemPrivate->extra->resourcesList)) {
qmlobject_disconnect(object, QObject, SIGNAL(destroyed(QObject*)),
quickItem, QQuickItem, SLOT(_q_resourceObjectDeleted(QObject*)));
}
@ -3497,8 +3448,7 @@ void QQuickItemPrivate::transform_clear(QQmlListProperty<QQuickTransform> *prop)
QQuickItem *that = static_cast<QQuickItem *>(prop->object);
QQuickItemPrivate *p = QQuickItemPrivate::get(that);
for (int ii = 0; ii < p->transforms.count(); ++ii) {
QQuickTransform *t = p->transforms.at(ii);
for (QQuickTransform *t : qAsConst(p->transforms)) {
QQuickTransformPrivate *tp = QQuickTransformPrivate::get(t);
tp->items.removeOne(that);
}
@ -3622,7 +3572,7 @@ QQuickAnchors *QQuickItemPrivate::anchors() const
void QQuickItemPrivate::siblingOrderChanged()
{
Q_Q(QQuickItem);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::SiblingOrder) {
change.listener->itemSiblingOrderChanged(q);
@ -3726,32 +3676,31 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
if (d->_anchors)
QQuickAnchorsPrivate::get(d->_anchors)->updateMe();
bool xChange = (newGeometry.x() != oldGeometry.x());
bool yChange = (newGeometry.y() != oldGeometry.y());
bool widthChange = (newGeometry.width() != oldGeometry.width());
bool heightChange = (newGeometry.height() != oldGeometry.height());
QQuickGeometryChange change;
QRectF diff(newGeometry.x() - oldGeometry.x(),
newGeometry.y() - oldGeometry.y(),
newGeometry.width() - oldGeometry.width(),
newGeometry.height() - oldGeometry.height());
change.setXChange(diff.x() != 0);
change.setYChange(diff.y() != 0);
change.setWidthChange(diff.width() != 0);
change.setHeightChange(diff.height() != 0);
const auto listeners = d->changeListeners;
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Geometry) {
if (change.gTypes == QQuickItemPrivate::GeometryChange) {
change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
} else if ((xChange && (change.gTypes & QQuickItemPrivate::XChange)) ||
(yChange && (change.gTypes & QQuickItemPrivate::YChange)) ||
(widthChange && (change.gTypes & QQuickItemPrivate::WidthChange)) ||
(heightChange && (change.gTypes & QQuickItemPrivate::HeightChange))) {
change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
}
const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &listener : listeners) {
if (listener.types & QQuickItemPrivate::Geometry) {
if (change.matches(listener.gTypes))
listener.listener->itemGeometryChanged(this, change, diff);
}
}
if (xChange)
if (change.xChange())
emit xChanged();
if (yChange)
if (change.yChange())
emit yChanged();
if (widthChange)
if (change.widthChange())
emit widthChanged();
if (heightChange)
if (change.heightChange())
emit heightChanged();
}
@ -3870,7 +3819,8 @@ void QQuickItemPrivate::removeItemChangeListener(QQuickItemChangeListener *liste
changeListeners.removeOne(change);
}
void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types)
void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener,
QQuickGeometryChange types)
{
ChangeListener change(listener, types);
int index = changeListeners.indexOf(change);
@ -3881,10 +3831,10 @@ void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListen
}
void QQuickItemPrivate::updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener,
GeometryChangeTypes types)
QQuickGeometryChange types)
{
ChangeListener change(listener, types);
if (types == NoChange) {
if (types.noChange()) {
changeListeners.removeOne(change);
} else {
int index = changeListeners.indexOf(change);
@ -4296,7 +4246,7 @@ void QQuickItem::setBaselineOffset(qreal offset)
d->baselineOffset = offset;
const auto listeners = d->changeListeners;
const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Geometry) {
QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
@ -4868,14 +4818,16 @@ void QQuickItem::componentComplete()
QQuickAnchorsPrivate::get(d->_anchors)->updateOnComplete();
}
if (d->extra.isAllocated() && d->extra->layer)
d->extra->layer->componentComplete();
if (d->extra.isAllocated()) {
if (d->extra->layer)
d->extra->layer->componentComplete();
if (d->extra.isAllocated() && d->extra->keyHandler)
d->extra->keyHandler->componentComplete();
if (d->extra->keyHandler)
d->extra->keyHandler->componentComplete();
if (d->extra.isAllocated() && d->extra->contents)
d->extra->contents->complete();
if (d->extra->contents)
d->extra->contents->complete();
}
if (d->window && d->dirtyAttributes) {
d->addToDirtyList();
@ -5773,8 +5725,9 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
}
bool childVisibilityChanged = false;
for (int ii = 0; ii < childItems.count(); ++ii)
childVisibilityChanged |= QQuickItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible);
for (QQuickItem *childItem : qAsConst(childItems)) {
childVisibilityChanged |= QQuickItemPrivate::get(childItem)->setEffectiveVisibleRecur(newEffectiveVisible);
}
itemChange(QQuickItem::ItemVisibleHasChanged, effectiveVisible);
#ifndef QT_NO_ACCESSIBILITY
@ -5823,8 +5776,8 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
}
}
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(
for (QQuickItem *childItem : qAsConst(childItems)) {
QQuickItemPrivate::get(childItem)->setEffectiveEnableRecur(
(flags & QQuickItem::ItemIsFocusScope) && scope ? q : scope, newEffectiveEnable);
}
@ -5968,7 +5921,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
switch (change) {
case QQuickItem::ItemChildAddedChange: {
q->itemChange(change, data);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Children) {
change.listener->itemChildAdded(q, data.item);
@ -5978,7 +5931,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
}
case QQuickItem::ItemChildRemovedChange: {
q->itemChange(change, data);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Children) {
change.listener->itemChildRemoved(q, data.item);
@ -5991,7 +5944,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
break;
case QQuickItem::ItemVisibleHasChanged: {
q->itemChange(change, data);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Visibility) {
change.listener->itemVisibilityChanged(q);
@ -6001,7 +5954,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
}
case QQuickItem::ItemParentHasChanged: {
q->itemChange(change, data);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Parent) {
change.listener->itemParentChanged(q, data.item);
@ -6011,7 +5964,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
}
case QQuickItem::ItemOpacityHasChanged: {
q->itemChange(change, data);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Opacity) {
change.listener->itemOpacityChanged(q);
@ -6024,7 +5977,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
break;
case QQuickItem::ItemRotationHasChanged: {
q->itemChange(change, data);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Rotation) {
change.listener->itemRotationChanged(q);
@ -6386,7 +6339,7 @@ void QQuickItem::resetWidth()
void QQuickItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickItem);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::ImplicitWidth) {
change.listener->itemImplicitWidthChanged(q);
@ -6550,7 +6503,7 @@ void QQuickItem::resetHeight()
void QQuickItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickItem);
const auto listeners = changeListeners;
const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::ImplicitHeight) {
change.listener->itemImplicitHeightChanged(q);
@ -7049,17 +7002,18 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
Q_Q(QQuickItem);
// if we're asked to turn it off (because of an unsetcursor call, or a node
// removal) then we should check our children and make sure it's really ok
// to turn it off.
if (!hasCursor && hasCursorInChild) {
foreach (QQuickItem *otherChild, childItems) {
// removal) then we should make sure it's really ok to turn it off.
if (!hasCursor && subtreeCursorEnabled) {
if (hasCursor)
return; // nope! sorry, I have a cursor myself
for (QQuickItem *otherChild : qAsConst(childItems)) {
QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild);
if (otherChildPrivate->hasCursorInChild)
if (otherChildPrivate->subtreeCursorEnabled || otherChildPrivate->hasCursor)
return; // nope! sorry, something else wants it kept on.
}
}
hasCursorInChild = hasCursor;
subtreeCursorEnabled = hasCursor;
QQuickItem *parent = q->parentItem();
if (parent) {
QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent);
@ -7077,7 +7031,7 @@ void QQuickItemPrivate::setHasHoverInChild(bool hasHover)
if (!hasHover && subtreeHoverEnabled) {
if (hoverEnabled)
return; // nope! sorry, I need hover myself
foreach (QQuickItem *otherChild, childItems) {
for (QQuickItem *otherChild : qAsConst(childItems)) {
QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild);
if (otherChildPrivate->subtreeHoverEnabled || otherChildPrivate->hoverEnabled)
return; // nope! sorry, something else wants it kept on.
@ -7098,7 +7052,7 @@ void QQuickItemPrivate::markObjects(QV4::ExecutionEngine *e)
Q_Q(QQuickItem);
QV4::QObjectWrapper::markWrapper(q, e);
foreach (QQuickItem *child, childItems)
for (QQuickItem *child : qAsConst(childItems))
QQuickItemPrivate::get(child)->markObjects(e);
}
@ -7266,25 +7220,7 @@ void QQuickItem::grabTouchPoints(const QVector<int> &ids)
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
QSet<QQuickItem*> ungrab;
for (int i = 0; i < ids.count(); ++i) {
QQuickItem *oldGrabber = windowPriv->itemForTouchPointId.value(ids.at(i));
if (oldGrabber == this)
return;
windowPriv->itemForTouchPointId[ids.at(i)] = this;
if (oldGrabber)
ungrab.insert(oldGrabber);
QQuickItem *mouseGrabber = d->window->mouseGrabberItem();
if (windowPriv->touchMouseId == ids.at(i) && mouseGrabber && mouseGrabber != this) {
qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: grabber" << mouseGrabber << "-> null";
mouseGrabber->ungrabMouse();
}
}
foreach (QQuickItem *oldGrabber, ungrab)
oldGrabber->touchUngrabEvent();
windowPriv->grabTouchPoints(this, ids);
}
/*!
@ -8162,7 +8098,7 @@ void QQuickItemLayer::itemOpacityChanged(QQuickItem *item)
updateOpacity();
}
void QQuickItemLayer::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &)
void QQuickItemLayer::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
{
updateGeometry();
}

View File

@ -98,7 +98,7 @@ public:
void complete();
protected:
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE;
void itemChildAdded(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
void itemChildRemoved(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
@ -188,7 +188,7 @@ public:
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
void itemOpacityChanged(QQuickItem *) Q_DECL_OVERRIDE;
void itemParentChanged(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE;
void itemSiblingOrderChanged(QQuickItem *) Q_DECL_OVERRIDE;
@ -318,24 +318,12 @@ public:
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
enum GeometryChangeType {
NoChange = 0,
XChange = 0x01,
YChange = 0x02,
WidthChange = 0x04,
HeightChange = 0x08,
SizeChange = WidthChange | HeightChange,
GeometryChange = XChange | YChange | SizeChange
};
Q_DECLARE_FLAGS(GeometryChangeTypes, GeometryChangeType)
struct ChangeListener {
ChangeListener(QQuickItemChangeListener *l = Q_NULLPTR, QQuickItemPrivate::ChangeTypes t = 0) : listener(l), types(t), gTypes(GeometryChange) {}
ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::GeometryChangeTypes gt) : listener(l), types(Geometry), gTypes(gt) {}
ChangeListener(QQuickItemChangeListener *l = nullptr, QQuickItemPrivate::ChangeTypes t = 0) : listener(l), types(t), gTypes(QQuickGeometryChange::All) {}
ChangeListener(QQuickItemChangeListener *l, QQuickGeometryChange gt) : listener(l), types(Geometry), gTypes(gt) {}
QQuickItemChangeListener *listener;
QQuickItemPrivate::ChangeTypes types;
QQuickItemPrivate::GeometryChangeTypes gTypes; //NOTE: not used for ==
QQuickGeometryChange gTypes; //NOTE: not used for ==
bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
};
@ -389,8 +377,8 @@ public:
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types);
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types);
void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types);
void updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types);
void updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types);
void updateOrRemoveGeometryChangeListener(QQuickItemChangeListener *listener, QQuickGeometryChange types);
QQuickStateGroup *_states();
QQuickStateGroup *_stateGroup;
@ -426,7 +414,7 @@ public:
bool isAccessible:1;
bool culled:1;
bool hasCursor:1;
bool hasCursorInChild:1;
bool subtreeCursorEnabled:1;
// Bit 32
bool subtreeHoverEnabled:1;
bool activeFocusOnTab:1;

View File

@ -58,12 +58,69 @@ QT_BEGIN_NAMESPACE
class QRectF;
class QQuickItem;
class QQuickAnchorsPrivate;
class QQuickGeometryChange
{
public:
enum Kind: int {
Nothing = 0x00,
X = 0x01,
Y = 0x02,
Width = 0x04,
Height = 0x08,
Size = Width | Height,
All = X | Y | Size
};
QQuickGeometryChange(int change = Nothing)
: kind(change)
{}
bool noChange() const { return kind == Nothing; }
bool anyChange() const { return !noChange(); }
bool xChange() const { return kind & X; }
bool yChange() const { return kind & Y; }
bool widthChange() const { return kind & Width; }
bool heightChange() const { return kind & Height; }
bool positionChange() const { return xChange() || yChange(); }
bool sizeChange() const { return widthChange() || heightChange(); }
bool horizontalChange() const { return xChange() || widthChange(); }
bool verticalChange() const { return yChange() || heightChange(); }
void setXChange(bool enabled) { set(X, enabled); }
void setYChange(bool enabled) { set(Y, enabled); }
void setWidthChange(bool enabled) { set(Width, enabled); }
void setHeightChange(bool enabled) { set(Height, enabled); }
void setSizeChange(bool enabled) { set(Size, enabled); }
void setAllChanged(bool enabled) { set(All, enabled); }
void setHorizontalChange(bool enabled) { set(X | Width, enabled); }
void setVerticalChange(bool enabled) { set(Y | Height, enabled); }
void set(int bits, bool enabled)
{
if (enabled) {
kind |= bits;
} else {
kind &= ~bits;
}
}
bool matches(QQuickGeometryChange other) const { return kind & other.kind; }
private:
int kind;
};
class QQuickItemChangeListener
{
public:
virtual ~QQuickItemChangeListener() {}
virtual void itemGeometryChanged(QQuickItem *, const QRectF & /* new */, const QRectF & /* old */ ) {}
virtual void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF & /* diff */) {}
virtual void itemSiblingOrderChanged(QQuickItem *) {}
virtual void itemVisibilityChanged(QQuickItem *) {}
virtual void itemOpacityChanged(QQuickItem *) {}

View File

@ -73,11 +73,11 @@
//#include <private/qquickpincharea_p.h>
#include <QtQuick/private/qquickcanvasitem_p.h>
#include <QtQuick/private/qquickcontext2d_p.h>
# include "qquickitemgrabresult.h"
#include "qquickitemgrabresult.h"
#include "qquicksprite_p.h"
#include "qquickspritesequence_p.h"
#include "qquickanimatedsprite_p.h"
#ifndef QT_NO_OPENGL
# include "qquicksprite_p.h"
# include "qquickspritesequence_p.h"
# include "qquickanimatedsprite_p.h"
# include "qquickopenglinfo_p.h"
#endif
#include "qquickgraphicsinfo_p.h"
@ -218,11 +218,11 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickPaintedItem>("QtQuick", 2, 0, "PaintedItem", QQuickPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
qmlRegisterType<QQuickCanvasItem>("QtQuick", 2, 0, "Canvas");
#ifndef QT_NO_OPENGL
qmlRegisterType<QQuickSprite>("QtQuick", 2, 0, "Sprite");
qmlRegisterType<QQuickAnimatedSprite>("QtQuick", 2, 0, "AnimatedSprite");
qmlRegisterType<QQuickSpriteSequence>("QtQuick", 2, 0, "SpriteSequence");
#endif
qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
qmlRegisterType<QQuickAnchorSet>();

View File

@ -1205,10 +1205,11 @@ void QQuickItemViewPrivate::showVisibleItems() const
}
}
void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &diff)
{
Q_Q(QQuickItemView);
QQuickFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
QQuickFlickablePrivate::itemGeometryChanged(item, change, diff);
if (!q->isComponentComplete())
return;

View File

@ -378,7 +378,7 @@ protected:
virtual void updateSectionCriteria() {}
virtual void updateSections() {}
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
};

View File

@ -131,7 +131,7 @@ public:
void updateAverage();
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE;
void fixupPosition() Q_DECL_OVERRIDE;
void fixup(AxisData &data, qreal minExtent, qreal maxExtent) Q_DECL_OVERRIDE;
bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
@ -1400,10 +1400,12 @@ bool QQuickListViewPrivate::hasStickyFooter() const
return footer && footerPositioning != QQuickListView::InlineFooter;
}
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &diff)
{
Q_Q(QQuickListView);
QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
QQuickItemViewPrivate::itemGeometryChanged(item, change, diff);
if (!q->isComponentComplete())
return;
@ -1417,29 +1419,31 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
}
if (item != contentItem && (!highlight || item != highlight->item)) {
if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
|| (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
if ((orient == QQuickListView::Vertical && change.heightChange())
|| (orient == QQuickListView::Horizontal && change.widthChange())) {
// if visibleItems.first() has resized, adjust its pos since it is used to
// position all subsequent items
if (visibleItems.count() && item == visibleItems.first()->item) {
FxListItemSG *listItem = static_cast<FxListItemSG*>(visibleItems.first());
const QRectF oldGeometry(item->x() - diff.x(),
item->y() - diff.y(),
item->width() - diff.width(),
item->height() - diff.height());
if (listItem->transitionScheduledOrRunning())
return;
if (orient == QQuickListView::Vertical) {
const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
qreal diff = newGeometry.height() - oldGeometry.height();
if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY())
listItem->setPosition(listItem->position() - diff, true);
listItem->setPosition(listItem->position() - diff.height(), true);
else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY())
listItem->setPosition(listItem->position() + diff, true);
listItem->setPosition(listItem->position() + diff.height(), true);
} else {
const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width();
qreal diff = newGeometry.width() - oldGeometry.width();
if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX())
listItem->setPosition(listItem->position() - diff, true);
listItem->setPosition(listItem->position() - diff.width(), true);
else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX())
listItem->setPosition(listItem->position() + diff, true);
listItem->setPosition(listItem->position() + diff.width(), true);
}
}
forceLayoutPolish();

View File

@ -65,11 +65,12 @@ QQuickLoaderPrivate::~QQuickLoaderPrivate()
disposeInitialPropertyValues();
}
void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change
, const QRectF &diff)
{
if (resizeItem == item)
_q_updateSize(false);
QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff);
}
void QQuickLoaderPrivate::itemImplicitWidthChanged(QQuickItem *)

View File

@ -84,7 +84,7 @@ public:
QQuickLoaderPrivate();
~QQuickLoaderPrivate();
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE;
void itemImplicitWidthChanged(QQuickItem *) Q_DECL_OVERRIDE;
void itemImplicitHeightChanged(QQuickItem *) Q_DECL_OVERRIDE;
void clear();

View File

@ -187,7 +187,7 @@ public:
explicit MappedSlotObject(PropChangedFunc func)
: QSlotObjectBase(&impl), _signalIndex(-1), func(func)
{}
{ ref(); }
void setSignalIndex(int idx) { _signalIndex = idx; }
int signalIndex() const { return _signalIndex; }
@ -215,6 +215,12 @@ private:
};
}
QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
{
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
clearSignalMappers(shaderType);
}
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
{
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
@ -363,7 +369,7 @@ void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item,
{
disconnectPropertySignals(item, shaderType);
uniformData[shaderType].clear();
signalMappers[shaderType].clear();
clearSignalMappers(shaderType);
if (shaderType == Key::VertexShader)
attributes.clear();
@ -593,6 +599,15 @@ void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item,
}
}
void QQuickOpenGLShaderEffectCommon::clearSignalMappers(int shader)
{
for (auto mapper : qAsConst(signalMappers[shader])) {
if (mapper)
mapper->destroyIfLastRef();
}
signalMappers[shader].clear();
}
QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent)
: QObject(parent)
, m_item(item)

View File

@ -84,6 +84,8 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
: host(host), mappedPropertyChanged(mappedPropertyChanged), fileSelector(nullptr)
{ }
~QQuickOpenGLShaderEffectCommon();
void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
@ -97,6 +99,8 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
void sourceDestroyed(QObject *object);
void propertyChanged(QQuickItem *item, const QMetaObject *itemMetaObject, int mappedId, bool *textureProviderChanged);
void clearSignalMappers(int shader);
QObject *host;
std::function<void(int)> mappedPropertyChanged;
Key source;

View File

@ -76,9 +76,8 @@ public:
void init();
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE {
if ((newGeometry.size() != oldGeometry.size())
&& (!highlightItem || item != highlightItem)) {
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE {
if (change.sizeChange() && (!highlightItem || item != highlightItem)) {
if (QQuickPathViewAttached *att = attached(item))
att->m_percent = -1;
scheduleLayout();

View File

@ -137,9 +137,9 @@ public:
setPositioningDirty();
}
void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE
{
if (newGeometry.size() != oldGeometry.size())
if (change.sizeChange())
setPositioningDirty();
}

View File

@ -56,9 +56,9 @@
#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgsoftwarerenderer_p.h>
#include <QtCore/private/qobject_p.h>
QT_BEGIN_NAMESPACE
#ifndef QT_NO_OPENGL
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@ -124,6 +124,10 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
To send events, for example mouse or keyboard events, to the scene, use
QCoreApplication::sendEvent() with the QQuickWindow instance as the receiver.
\note In general QQuickRenderControl is supported in combination with all Qt
Quick backends. However, some functionality, in particular grab(), may not be
available in all cases.
\inmodule QtQuick
*/
@ -209,8 +213,9 @@ void QQuickRenderControl::prepareThread(QThread *targetThread)
}
/*!
Initializes the scene graph resources. The context \a gl has to
be the current context.
Initializes the scene graph resources. The context \a gl has to be the
current OpenGL context or null if it is not relevant because a Qt Quick
backend other than OpenGL is in use.
\note Qt Quick does not take ownership of the context. It is up to the
application to destroy it after a call to invalidate() or after the
@ -369,12 +374,31 @@ QImage QQuickRenderControl::grab()
if (!d->window)
return QImage();
render();
QImage grabContent;
if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) {
#ifndef QT_NO_OPENGL
QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
#else
QImage grabContent = d->window->grabWindow();
render();
grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
#endif
} else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
if (softwareRenderer) {
const qreal dpr = d->window->effectiveDevicePixelRatio();
const QSize imageSize = d->window->size() * dpr;
grabContent = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
grabContent.setDevicePixelRatio(dpr);
QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
softwareRenderer->setCurrentPaintDevice(&grabContent);
softwareRenderer->markDirty();
render();
softwareRenderer->setCurrentPaintDevice(prevDev);
}
} else {
qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend");
}
return grabContent;
}

View File

@ -432,7 +432,9 @@ QT_BEGIN_NAMESPACE
do its job. The selector-less version is the GLSL source, while the \c hlsl
selector is used when running on the D3D12 backend. The file under
\c{+hlsl} can then contain either HLSL source code or compiled bytecode
from the \c fxc tool.
from the \c fxc tool. Additionally, when using a version 3.2 or newer core
profile context with OpenGL, GLSL sources with a core profile compatible
syntax can be placed under \c{+glslcore}.
\qml
import QtQuick 2.8 // for GraphicsInfo

View File

@ -308,11 +308,11 @@ QQuickItem *QQuickShaderEffectSource::sourceItem() const
return m_sourceItem;
}
void QQuickShaderEffectSource::itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect)
void QQuickShaderEffectSource::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
{
Q_ASSERT(item == m_sourceItem);
Q_UNUSED(item);
if (newRect.size() != oldRect.size())
if (change.sizeChange())
update();
}

View File

@ -168,7 +168,7 @@ protected:
void releaseResources() Q_DECL_OVERRIDE;
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) Q_DECL_OVERRIDE;
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) Q_DECL_OVERRIDE;
void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
private:

View File

@ -300,7 +300,7 @@ private Q_SLOTS:
private:
friend class QQuickImageParticle;
friend class QQuickSpriteSequence;
//friend class QQuickSpriteSequence;
friend class QQuickAnimatedSprite;
friend class QQuickSpriteEngine;
friend class QQuickStochasticEngine;

View File

@ -372,7 +372,7 @@ void QQuickSpriteEngine::startAssemblingImage()
m_startedImageAssembly = true;
}
QImage QQuickSpriteEngine::assembledImage()
QImage QQuickSpriteEngine::assembledImage(int maxSize)
{
QQuickPixmap::Status stat = status();
if (!m_errorsPrinted && stat == QQuickPixmap::Error) {
@ -389,19 +389,7 @@ QImage QQuickSpriteEngine::assembledImage()
int w = 0;
m_maxFrames = 0;
m_imageStateCount = 0;
int maxSize = 0;
#ifndef QT_NO_OPENGL
//If there is no current OpenGL Context
if (!QOpenGLContext::currentContext())
return QImage();
QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
#else
maxSize = 2048;
#endif
#ifdef SPRITE_IMAGE_DEBUG
qDebug() << "MAX TEXTURE SIZE" << maxSize;
#endif
foreach (QQuickSprite* state, m_sprites){
if (state->frames() > m_maxFrames)
m_maxFrames = state->frames();

View File

@ -295,7 +295,7 @@ public:
bool isError() { return status() == QQuickPixmap::Error; }
QQuickPixmap::Status status();//Composed status of all Sprites
void startAssemblingImage();
QImage assembledImage();
QImage assembledImage(int maxSize = 2048);
private:
int pseudospriteProgress(int,int,int*rd=0);

Some files were not shown because too many files have changed in this diff Show More