Merge remote-tracking branch 'origin/dev' into HEAD
Change-Id: I931a7b264c68c40e16d9467b48173311aef74bd0
This commit is contained in:
commit
ac79c052af
|
@ -1,4 +1,4 @@
|
|||
SOURCES = d3d12.cpp
|
||||
CONFIG -= qt dylib
|
||||
CONFIG += console
|
||||
LIBS += -ldxgi -ld3d12
|
||||
LIBS += -ldxgi -ld3d12 -ld3dcompiler -ldcomp
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -75,6 +75,8 @@ public:
|
|||
QSGRectangleNode *createRectangleNode() override;
|
||||
QSGImageNode *createImageNode() override;
|
||||
QSGNinePatchNode *createNinePatchNode() override;
|
||||
QSGSpriteNode *createSpriteNode() override;
|
||||
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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), ¬InRevision) : defaultProperty;
|
||||
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : 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), ¬InRevision) : defaultProperty;
|
||||
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : 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), ¬InRevision);
|
||||
} 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "qv4engine_p.h"
|
||||
#include "qv4scopedvalue_p.h"
|
||||
#include "qv4value_p.h"
|
||||
#include "qv4internalclass_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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<>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
||||
*/
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *) {}
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 *)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue