aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp4
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp4
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h8
-rw-r--r--src/quick/items/qquickcanvas.cpp166
-rw-r--r--src/quick/items/qquickcanvas.h6
-rw-r--r--src/quick/items/qquickcanvas_p.h7
-rw-r--r--src/quick/items/qquickflickable.cpp50
-rw-r--r--src/quick/items/qquickitem.cpp299
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickitem_p.h14
-rw-r--r--src/quick/items/qquickitemanimation.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp12
-rw-r--r--src/quick/items/qquickloader.cpp12
-rw-r--r--src/quick/items/qquickpathview.cpp3
-rw-r--r--src/quick/items/qquickshadereffect.cpp57
-rw-r--r--src/quick/items/qquickshadereffect_p.h3
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp14
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp108
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h7
-rw-r--r--src/quick/items/qquicksprite.cpp12
-rw-r--r--src/quick/items/qquickspriteengine.cpp4
-rw-r--r--src/quick/items/qquickspriteengine_p.h2
-rw-r--r--src/quick/items/qquickspriteimage.cpp2
-rw-r--r--src/quick/items/qquicktext.cpp51
-rw-r--r--src/quick/items/qquicktextcontrol.cpp127
-rw-r--r--src/quick/items/qquicktextcontrol_p.h23
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h4
-rw-r--r--src/quick/items/qquicktextedit.cpp18
-rw-r--r--src/quick/items/qquicktextedit_p_p.h3
-rw-r--r--src/quick/items/qquicktextinput.cpp110
-rw-r--r--src/quick/items/qquicktextinput_p_p.h7
-rw-r--r--src/quick/items/qquickvisualadaptormodel.cpp3
-rw-r--r--src/quick/items/qquickwindowmanager.cpp8
34 files changed, 759 insertions, 394 deletions
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index f8e5e3c57f..a605b9ce6d 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -63,6 +63,10 @@
#include <private/qv8domerrors_p.h>
#include <QtCore/qnumeric.h>
+#ifdef Q_OS_QNX
+#include <ctype.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
\qmlclass Context2D QQuickContext2D
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 46f85417d2..27efebca0c 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -144,6 +144,10 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
// Enable accessibility for items with accessible content. This also
// enables accessibility for the ancestors of souch items.
item->d_func()->setAccessibleFlagAndListener();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(item, QAccessible::ObjectCreated);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
QQuickAccessibleAttached::~QQuickAccessibleAttached()
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 129c3ef240..419f21a4b3 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -85,6 +85,10 @@ public:
if (name != m_name) {
m_name = name;
emit nameChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(parent(), QAccessible::NameChanged);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
}
@@ -94,6 +98,10 @@ public:
if (m_description != description) {
m_description = description;
emit descriptionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(parent(), QAccessible::DescriptionChanged);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
}
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
index cd3bbbfa2a..a11f68f709 100644
--- a/src/quick/items/qquickcanvas.cpp
+++ b/src/quick/items/qquickcanvas.cpp
@@ -306,6 +306,8 @@ QQuickCanvasPrivate::QQuickCanvasPrivate()
, windowManager(0)
, clearColor(Qt::white)
, clearBeforeRendering(true)
+ , persistentGLContext(false)
+ , persistentSceneGraph(false)
, renderTarget(0)
, renderTargetId(0)
, incubationController(0)
@@ -325,6 +327,7 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c)
rootItem = new QQuickRootItem;
QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
rootItemPrivate->canvas = q;
+ rootItemPrivate->canvasRefCount = 1;
rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
// In the absence of a focus in event on some platforms assume the window will
@@ -536,7 +539,7 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
q->sendEvent(oldActiveFocusItem, &event);
QQuickItem *afi = oldActiveFocusItem;
- while (afi != scope) {
+ while (afi && afi != scope) {
if (QQuickItemPrivate::get(afi)->activeFocus) {
QQuickItemPrivate::get(afi)->activeFocus = false;
changed << afi;
@@ -548,27 +551,12 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F
if (item != rootItem && !(options & DontChangeSubFocusItem)) {
QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- // Correct focus chain in scope
- if (oldSubFocusItem) {
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
- sfi = sfi->parentItem();
- }
- }
- {
- scopePrivate->subFocusItem = item;
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = item;
- sfi = sfi->parentItem();
- }
- }
-
if (oldSubFocusItem) {
QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
changed << oldSubFocusItem;
}
+
+ QQuickItemPrivate::get(item)->updateSubFocusItem(scope, true);
}
if (!(options & DontChangeFocusProperty)) {
@@ -647,7 +635,7 @@ void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
q->sendEvent(oldActiveFocusItem, &event);
QQuickItem *afi = oldActiveFocusItem;
- while (afi != scope) {
+ while (afi && afi != scope) {
if (QQuickItemPrivate::get(afi)->activeFocus) {
QQuickItemPrivate::get(afi)->activeFocus = false;
changed << afi;
@@ -658,20 +646,13 @@ void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
if (item != rootItem && !(options & DontChangeSubFocusItem)) {
QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
- // Correct focus chain in scope
- if (oldSubFocusItem) {
- QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
- while (sfi != scope) {
- QQuickItemPrivate::get(sfi)->subFocusItem = 0;
- sfi = sfi->parentItem();
- }
- }
- scopePrivate->subFocusItem = 0;
-
if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
changed << oldSubFocusItem;
}
+
+ QQuickItemPrivate::get(item)->updateSubFocusItem(scope, false);
+
} else if (!(options & DontChangeFocusProperty)) {
QQuickItemPrivate::get(item)->focus = false;
changed << item;
@@ -750,6 +731,55 @@ void QQuickCanvasPrivate::cleanup(QSGNode *n)
reparent the items to the root item or to an existing item in the scene.
For easily displaying a scene from a QML file, see \l{QQuickView}.
+
+
+ \section1 Scene Graph and Rendering
+
+ The QQuickCanvas uses a scene graph on top of OpenGL to render. This scene graph is disconnected
+ from the QML scene and potentially lives in another thread, depending on the platform
+ implementation. Since the rendering scene graph lives independently from the QML scene, it can
+ also be completely released without affecting the state of the QML scene.
+
+ The sceneGraphInitialized() signal is emitted on the rendering thread before the QML scene is
+ rendered to the screen for the first time. If the rendering scene graph has been released
+ the signal will be emitted again before the next frame is rendered.
+
+ Rendering is done by first copying the QML scene's state into the rendering scene graph. This is
+ done by calling QQuickItem::updatePaintNode() functions on all items that have changed. This phase
+ is run on the rendering thread with the GUI thread blocked, when a separate rendering thread
+ is being used. The scene can then be rendered.
+
+ Before the scene graph is rendered, the beforeRendering() signal is emitted. The OpenGL context
+ is bound at this point and the application is free to do its own rendering. Also
+ make sure to disable the clearing of the color buffer, using setClearBeforeRendering(). The
+ default clear color is white and can be changed with setClearColor(). After the scene has
+ been rendered, the afterRendering() signal is emitted. The application can use this to render
+ OpenGL on top of a QML application. Once the frame is fully done and has been swapped,
+ the frameSwapped() signal is emitted.
+
+ While the scene graph is being rendered on the rendering thread, the GUI will process animations
+ for the next frame. This means that as long as users are not using scene graph API
+ directly, the added complexity of a rendering thread can be completely ignored.
+
+ When a QQuickCanvas is programatically hidden with hide() or setVisible(false), it will
+ stop rendering and its scene graph and OpenGL context might be released. The
+ sceneGraphInvalidated() signal will be emitted when this happens.
+
+ \warning It is crucial that OpenGL operations and interaction with the scene graph happens
+ exclusively on the rendering thread, primarily during the updatePaintNode() phase.
+
+ \warning As signals related to rendering might be emitted from the rendering thread,
+ connections should be made using Qt::DirectConnection
+
+
+ \section1 Resource Management
+
+ QML will typically try to cache images, scene graph nodes, etc to improve performance, but in
+ some low-memory scenarios it might be required to aggressively release these resources. The
+ releaseResources() can be used to force clean up of certain resources. Calling releaseResources()
+ may result in the entire scene graph and its OpenGL context being deleted. The
+ sceneGraphInvalidated() signal will be emitted when this happens.
+
*/
QQuickCanvas::QQuickCanvas(QWindow *parent)
: QWindow(*(new QQuickCanvasPrivate), parent)
@@ -771,11 +801,6 @@ QQuickCanvas::~QQuickCanvas()
d->windowManager->canvasDestroyed(this);
- // ### should we change ~QQuickItem to handle this better?
- // manually cleanup for the root item (item destructor only handles these when an item is parented)
- QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
- rootItemPrivate->removeFromDirtyList();
-
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete d->incubationController; d->incubationController = 0;
@@ -786,6 +811,15 @@ QQuickCanvas::~QQuickCanvas()
/*!
This function tries to release redundant resources currently held by the QML scene.
+
+ Calling this function might result in the scene graph and the OpenGL context used
+ for rendering being released to release graphics memory. If this happens, the
+ sceneGraphInvalidated() signal will be called, allowing users to clean up their
+ own graphics resources. The setPersistentOpenGLContext() and setPersistentSceneGraph()
+ functions can be used to prevent this from happening, if handling the cleanup is
+ not feasible in the application, at the cost of higher memory usage.
+
+ \sa sceneGraphInvalidated(), setPersistentOpenGLContext(), setPersistentSceneGraph().
*/
void QQuickCanvas::releaseResources()
@@ -798,6 +832,69 @@ void QQuickCanvas::releaseResources()
/*!
+ Controls whether the OpenGL context can be released as a part of a call to
+ releaseResources().
+
+ The OpenGL context might still be released when the user makes an explicit
+ call to hide().
+
+ \sa setPersistentSceneGraph()
+ */
+
+void QQuickCanvas::setPersistentOpenGLContext(bool persistent)
+{
+ Q_D(QQuickCanvas);
+ d->persistentGLContext = persistent;
+}
+
+
+/*!
+ Returns whether the OpenGL context can be released as a part of a call to
+ releaseResources().
+ */
+
+bool QQuickCanvas::isPersistentOpenGLContext() const
+{
+ Q_D(const QQuickCanvas);
+ return d->persistentGLContext;
+}
+
+
+
+/*!
+ Controls whether the scene graph nodes and resources can be released as a
+ part of a call to releaseResources().
+
+ The scene graph nodes and resources might still be released when the user
+ makes an explicit call to hide().
+
+ \sa setPersistentOpenGLContext()
+ */
+
+void QQuickCanvas::setPersistentSceneGraph(bool persistent)
+{
+ Q_D(QQuickCanvas);
+ d->persistentSceneGraph = persistent;
+}
+
+
+
+/*!
+ Returns whether the scene graph nodes and resources can be released as a part
+ of a call to releaseResources().
+ */
+
+bool QQuickCanvas::isPersistentSceneGraph() const
+{
+ Q_D(const QQuickCanvas);
+ return d->persistentSceneGraph;
+}
+
+
+
+
+
+/*!
Returns the invisible root item of the scene.
A QQuickCanvas always has a single invisible root item. To add items to this canvas,
@@ -1618,6 +1715,7 @@ void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
if (p->extra.isAllocated()) {
p->extra->opacityNode = 0;
p->extra->clipNode = 0;
+ p->extra->rootNode = 0;
}
p->groupNode = 0;
diff --git a/src/quick/items/qquickcanvas.h b/src/quick/items/qquickcanvas.h
index 4ac9509896..787bb7e3c7 100644
--- a/src/quick/items/qquickcanvas.h
+++ b/src/quick/items/qquickcanvas.h
@@ -114,6 +114,12 @@ public:
void setClearColor(const QColor &color);
QColor clearColor() const;
+ void setPersistentOpenGLContext(bool persistent);
+ bool isPersistentOpenGLContext() const;
+
+ void setPersistentSceneGraph(bool persistent);
+ bool isPersistentSceneGraph() const;
+
QOpenGLContext *openglContext() const;
Q_SIGNALS:
diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h
index 147526466e..643d694400 100644
--- a/src/quick/items/qquickcanvas_p.h
+++ b/src/quick/items/qquickcanvas_p.h
@@ -144,7 +144,7 @@ public:
void setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions = 0);
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions = 0);
- void notifyFocusChangesRecur(QQuickItem **item, int remaining);
+ static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
void updateFocusItemTransform();
@@ -184,6 +184,11 @@ public:
uint clearBeforeRendering : 1;
+ // Currently unused in the default implementation, as we're not stopping
+ // rendering when obscured as we should...
+ uint persistentGLContext : 1;
+ uint persistentSceneGraph : 1;
+
QOpenGLFramebufferObject *renderTarget;
uint renderTargetId;
QSize renderTargetSize;
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index b6d3ebd7f2..62d0e4aa41 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -887,11 +887,11 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
bool stealY = stealMouse;
bool stealX = stealMouse;
- qint64 elapsed = computeCurrentTime(event) - lastPressTime;
+ qint64 elapsedSincePress = computeCurrentTime(event) - lastPressTime;
if (q->yflick()) {
qreal dy = event->localPos().y() - pressPos.y();
- if (qAbs(dy) > qApp->styleHints()->startDragDistance() || elapsed > 200) {
+ if (qAbs(dy) > qApp->styleHints()->startDragDistance() || elapsedSincePress > 200) {
if (!vMoved)
vData.dragStartOffset = dy;
qreal newY = dy + vData.pressPos - vData.dragStartOffset;
@@ -924,7 +924,7 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
if (q->xflick()) {
qreal dx = event->localPos().x() - pressPos.x();
- if (qAbs(dx) > qApp->styleHints()->startDragDistance() || elapsed > 200) {
+ if (qAbs(dx) > qApp->styleHints()->startDragDistance() || elapsedSincePress > 200) {
if (!hMoved)
hData.dragStartOffset = dx;
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
@@ -974,28 +974,26 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
q->movementStarting();
}
- if (!lastPos.isNull()) {
- qint64 currentTimestamp = computeCurrentTime(event);
- qreal elapsed = qreal(currentTimestamp - lastPosTime) / 1000.;
- if (elapsed <= 0)
- return;
- lastPosTime = currentTimestamp;
- QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
- if (q->yflick() && !rejectY) {
- if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
- vData.addVelocitySample(extended->velocity().y(), maxVelocity);
- } else {
- qreal dy = event->localPos().y()-lastPos.y();
- vData.addVelocitySample(dy/elapsed, maxVelocity);
- }
+ qint64 currentTimestamp = computeCurrentTime(event);
+ qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
+ if (elapsed <= 0)
+ return;
+ lastPosTime = currentTimestamp;
+ QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
+ if (q->yflick() && !rejectY) {
+ if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
+ vData.addVelocitySample(extended->velocity().y(), maxVelocity);
+ } else {
+ qreal dy = event->localPos().y() - (lastPos.isNull() ? pressPos.y() : lastPos.y());
+ vData.addVelocitySample(dy/elapsed, maxVelocity);
}
- if (q->xflick() && !rejectX) {
- if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
- hData.addVelocitySample(extended->velocity().x(), maxVelocity);
- } else {
- qreal dx = event->localPos().x()-lastPos.x();
- hData.addVelocitySample(dx/elapsed, maxVelocity);
- }
+ }
+ if (q->xflick() && !rejectX) {
+ if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
+ hData.addVelocitySample(extended->velocity().x(), maxVelocity);
+ } else {
+ qreal dx = event->localPos().x() - (lastPos.isNull() ? pressPos.x() : lastPos.x());
+ hData.addVelocitySample(dx/elapsed, maxVelocity);
}
}
@@ -1763,6 +1761,10 @@ void QQuickFlickable::mouseUngrabEvent()
d->draggingEnding();
d->stealMouse = false;
setKeepMouseGrab(false);
+ d->fixupX();
+ d->fixupY();
+ if (!d->timeline.isActive())
+ movementEnding();
}
}
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 423fb0f40c..2a744c0559 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -1621,6 +1621,36 @@ void QQuickItemPrivate::setAccessibleFlagAndListener()
}
}
+void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
+{
+ Q_Q(QQuickItem);
+ Q_ASSERT(scope);
+
+ QQuickItemPrivate *scopePrivate = QQuickItemPrivate::get(scope);
+
+ QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
+ // Correct focus chain in scope
+ if (oldSubFocusItem) {
+ QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi && sfi != scope) {
+ QQuickItemPrivate::get(sfi)->subFocusItem = 0;
+ sfi = sfi->parentItem();
+ }
+ }
+
+ if (focus) {
+ scopePrivate->subFocusItem = q;
+ QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi && sfi != scope) {
+ QQuickItemPrivate::get(sfi)->subFocusItem = q;
+ sfi = sfi->parentItem();
+ }
+ } else {
+ scopePrivate->subFocusItem = 0;
+ }
+}
+
+
/*!
\class QQuickItem
\brief The QQuickItem class provides the most basic of all visual items in QML.
@@ -1794,10 +1824,13 @@ QQuickItem::~QQuickItem()
Q_D(QQuickItem);
+ if (d->canvasRefCount > 1)
+ d->canvasRefCount = 1; // Make sure canvas is set to null in next call to derefCanvas().
if (d->parentItem)
setParentItem(0);
- else if (d->canvas && d->itemNodeInstance)
- QQuickCanvasPrivate::get(d->canvas)->cleanup(d->itemNodeInstance); // cleanup root
+ else if (d->canvas)
+ d->derefCanvas();
+
// XXX todo - optimize
while (!d->childItems.isEmpty())
d->childItems.first()->setParentItem(0);
@@ -1894,19 +1927,22 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
QQuickItem *scopeItem = 0;
- if (d->canvas && hasFocus()) {
- scopeItem = oldParentItem;
- while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ if (hasFocus())
scopeFocusedItem = this;
- } else if (d->canvas && !isFocusScope() && d->subFocusItem) {
- scopeItem = oldParentItem;
- while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ else if (!isFocusScope() && d->subFocusItem)
scopeFocusedItem = d->subFocusItem;
- }
- if (scopeFocusedItem)
- QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
+ if (scopeFocusedItem) {
+ scopeItem = oldParentItem;
+ while (!scopeItem->isFocusScope() && scopeItem->parentItem())
+ scopeItem = scopeItem->parentItem();
+ if (d->canvas) {
+ QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
QQuickCanvasPrivate::DontChangeFocusProperty);
+ } else {
+ QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, false);
+ }
+ }
const bool wasVisible = isVisible();
op->removeChild(this);
@@ -1917,35 +1953,54 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
QQuickCanvasPrivate::get(d->canvas)->parentlessItems.remove(this);
}
- d->parentItem = parentItem;
-
- QQuickCanvas *parentCanvas = parentItem?QQuickItemPrivate::get(parentItem)->canvas:0;
- if (d->canvas != parentCanvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, parentCanvas);
+ QQuickCanvas *oldParentCanvas = oldParentItem ? QQuickItemPrivate::get(oldParentItem)->canvas : 0;
+ QQuickCanvas *parentCanvas = parentItem ? QQuickItemPrivate::get(parentItem)->canvas : 0;
+ if (oldParentCanvas == parentCanvas) {
+ // Avoid freeing and reallocating resources if the canvas stays the same.
+ d->parentItem = parentItem;
+ } else {
+ if (oldParentCanvas)
+ d->derefCanvas();
+ d->parentItem = parentItem;
+ if (parentCanvas)
+ d->refCanvas(parentCanvas);
}
d->dirty(QQuickItemPrivate::ParentChanged);
if (d->parentItem)
QQuickItemPrivate::get(d->parentItem)->addChild(this);
+ else if (d->canvas)
+ QQuickCanvasPrivate::get(d->canvas)->parentlessItems.insert(this);
d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
d->setEffectiveEnableRecur(0, d->calcEffectiveEnable());
- if (scopeFocusedItem && d->parentItem && d->canvas) {
- // We need to test whether this item becomes scope focused
- QQuickItem *scopeItem = 0;
- scopeItem = d->parentItem;
- while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ if (d->parentItem) {
+ if (!scopeFocusedItem) {
+ if (hasFocus())
+ scopeFocusedItem = this;
+ else if (!isFocusScope() && d->subFocusItem)
+ scopeFocusedItem = d->subFocusItem;
+ }
- if (scopeItem->scopedFocusItem()) {
- QQuickItemPrivate::get(scopeFocusedItem)->focus = false;
- emit scopeFocusedItem->focusChanged(false);
- } else {
- QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scopeItem, scopeFocusedItem,
- QQuickCanvasPrivate::DontChangeFocusProperty);
+ if (scopeFocusedItem) {
+ // We need to test whether this item becomes scope focused
+ QQuickItem *scopeItem = d->parentItem;
+ while (!scopeItem->isFocusScope() && scopeItem->parentItem())
+ scopeItem = scopeItem->parentItem();
+
+ if (scopeItem->scopedFocusItem()) {
+ QQuickItemPrivate::get(scopeFocusedItem)->focus = false;
+ emit scopeFocusedItem->focusChanged(false);
+ } else {
+ if (d->canvas) {
+ QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scopeItem, scopeFocusedItem,
+ QQuickCanvasPrivate::DontChangeFocusProperty);
+ } else {
+ QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, true);
+ }
+ }
}
}
@@ -2129,30 +2184,82 @@ QQuickItem *QQuickItemPrivate::InitializationState::getFocusScope(QQuickItem *it
return focusScope;
}
-void QQuickItemPrivate::initCanvas(InitializationState *state, QQuickCanvas *c)
+void QQuickItemPrivate::refCanvas(InitializationState *state, QQuickCanvas *c)
{
- Q_Q(QQuickItem);
+ // An item needs a canvas if it is referenced by another item which has a canvas.
+ // Typically the item is referenced by a parent, but can also be referenced by a
+ // ShaderEffect or ShaderEffectSource. 'canvasRefCount' counts how many items with
+ // a canvas is referencing this item. When the reference count goes from zero to one,
+ // or one to zero, the canvas of this item is updated and propagated to the children.
+ // As long as the reference count stays above zero, the canvas is unchanged.
+ // refCanvas() increments the reference count.
+ // derefCanvas() decrements the reference count.
- if (canvas) {
- removeFromDirtyList();
- QQuickCanvasPrivate *c = QQuickCanvasPrivate::get(canvas);
- if (polishScheduled)
- c->itemsToPolish.remove(q);
- if (c->mouseGrabberItem == q)
- c->mouseGrabberItem = 0;
- if ( hoverEnabled )
- c->hoverItems.removeAll(q);
- if (itemNodeInstance)
- c->cleanup(itemNodeInstance);
- if (!parentItem)
- c->parentlessItems.remove(q);
+ Q_Q(QQuickItem);
+ Q_ASSERT((canvas != 0) == (canvasRefCount > 0));
+ Q_ASSERT(c);
+ if (++canvasRefCount > 1) {
+ if (c != canvas)
+ qWarning("QQuickItem: Cannot use same item on different canvases at the same time.");
+ return; // Canvas already set.
}
+ Q_ASSERT(canvas == 0);
canvas = c;
- if (canvas && polishScheduled)
+ if (polishScheduled)
QQuickCanvasPrivate::get(canvas)->itemsToPolish.insert(q);
+ InitializationState _dummy;
+ InitializationState *childState = state;
+
+ if (q->isFocusScope()) {
+ _dummy.clear(q);
+ childState = &_dummy;
+ }
+
+ if (!parentItem)
+ QQuickCanvasPrivate::get(canvas)->parentlessItems.insert(q);
+
+ for (int ii = 0; ii < childItems.count(); ++ii) {
+ QQuickItem *child = childItems.at(ii);
+ QQuickItemPrivate::get(child)->refCanvas(childState, c);
+ }
+
+ dirty(Canvas);
+
+ if (extra.isAllocated() && extra->screenAttached)
+ extra->screenAttached->canvasChanged(c);
+ itemChange(QQuickItem::ItemSceneChange, c);
+}
+
+void QQuickItemPrivate::derefCanvas()
+{
+ Q_Q(QQuickItem);
+ Q_ASSERT((canvas != 0) == (canvasRefCount > 0));
+
+ if (!canvas)
+ return; // This can happen when destroying recursive shader effect sources.
+
+ if (--canvasRefCount > 0)
+ return; // There are still other references, so don't set canvas to null yet.
+
+ q->releaseResources();
+ removeFromDirtyList();
+ QQuickCanvasPrivate *c = QQuickCanvasPrivate::get(canvas);
+ if (polishScheduled)
+ c->itemsToPolish.remove(q);
+ if (c->mouseGrabberItem == q)
+ c->mouseGrabberItem = 0;
+ if ( hoverEnabled )
+ c->hoverItems.removeAll(q);
+ if (itemNodeInstance)
+ c->cleanup(itemNodeInstance);
+ if (!parentItem)
+ c->parentlessItems.remove(q);
+
+ canvas = 0;
+
itemNodeInstance = 0;
if (extra.isAllocated()) {
@@ -2165,39 +2272,19 @@ void QQuickItemPrivate::initCanvas(InitializationState *state, QQuickCanvas *c)
groupNode = 0;
paintNode = 0;
- InitializationState _dummy;
- InitializationState *childState = state;
-
- if (c && q->isFocusScope()) {
- _dummy.clear(q);
- childState = &_dummy;
- }
-
- if (!parentItem && canvas)
- QQuickCanvasPrivate::get(canvas)->parentlessItems.insert(q);
-
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItem *child = childItems.at(ii);
- QQuickItemPrivate::get(child)->initCanvas(childState, c);
- }
-
- if (c && focus) {
- // Fixup
- if (state->getFocusScope(q)->scopedFocusItem()) {
- focus = false;
- emit q->focusChanged(false);
- } else {
- QQuickCanvasPrivate::get(canvas)->setFocusInScope(state->getFocusScope(q), q);
- }
+ QQuickItemPrivate::get(child)->derefCanvas();
}
dirty(Canvas);
if (extra.isAllocated() && extra->screenAttached)
- extra->screenAttached->canvasChanged(c);
- itemChange(QQuickItem::ItemSceneChange, c);
+ extra->screenAttached->canvasChanged(0);
+ itemChange(QQuickItem::ItemSceneChange, (QQuickCanvas *)0);
}
+
/*!
Returns a transform that maps points from canvas space into item space.
*/
@@ -2300,7 +2387,7 @@ bool QQuickItem::isComponentComplete() const
QQuickItemPrivate::QQuickItemPrivate()
: _anchors(0), _stateGroup(0),
flags(0), widthValid(false), heightValid(false), baselineOffsetValid(false), componentComplete(true),
- keepMouse(false), keepTouch(false), hoverEnabled(false), smooth(false), focus(false), activeFocus(false), notifiedFocus(false),
+ keepMouse(false), keepTouch(false), hoverEnabled(false), smooth(true), focus(false), activeFocus(false), notifiedFocus(false),
notifiedActiveFocus(false), filtersChildMouseEvents(false), explicitVisible(true),
effectiveVisible(true), explicitEnable(true), effectiveEnable(true), polishScheduled(false),
inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true),
@@ -2310,7 +2397,7 @@ QQuickItemPrivate::QQuickItemPrivate()
dirtyAttributes(0), nextDirtyItem(0), prevDirtyItem(0),
- canvas(0), parentItem(0), sortedChildItems(&childItems),
+ canvas(0), canvasRefCount(0), parentItem(0), sortedChildItems(&childItems),
subFocusItem(0),
@@ -2954,6 +3041,23 @@ QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
return 0;
}
+/*!
+ This function is called when the item's scene graph resources are no longer needed.
+ It allows items to free its resources, for instance textures, that are not owned by scene graph
+ nodes. Note that scene graph nodes are managed by QQuickCanvas and should not be deleted by
+ this function. Scene graph resources are no longer needed when the parent is set to null and
+ the item is not used by any \l ShaderEffect or \l ShaderEffectSource.
+
+ This function is called from the main thread. Therefore, resources used by the scene graph
+ should not be deleted directly, but by calling \l QObject::deleteLater().
+
+ \note The item destructor still needs to free its scene graph resources if not already done.
+ */
+
+void QQuickItem::releaseResources()
+{
+}
+
QSGTransformNode *QQuickItemPrivate::createTransformNode()
{
return new QSGTransformNode;
@@ -3018,6 +3122,10 @@ void QQuickItem::inputMethodEvent(QInputMethodEvent *event)
void QQuickItem::focusInEvent(QFocusEvent *)
{
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleEvent ev(this, QAccessible::Focus);
+ QAccessible::updateAccessibility(&ev);
+#endif
}
void QQuickItem::focusOutEvent(QFocusEvent *)
@@ -3988,7 +4096,12 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
childVisibilityChanged |= QQuickItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible);
itemChange(QQuickItem::ItemVisibleHasChanged, effectiveVisible);
-
+#ifndef QT_NO_ACCESSIBILITY
+ if (isAccessible) {
+ QAccessibleEvent ev(q, effectiveVisible ? QAccessible::ObjectShow : QAccessible::ObjectHide);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
emit q->visibleChanged();
if (childVisibilityChanged)
emit q->visibleChildrenChanged();
@@ -4217,13 +4330,15 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
/*!
\property QQuickItem::smooth
- \brief whether the item is smoothly transformed.
+ \brief whether the item is smoothed or not.
- This property is provided purely for the purpose of optimization. Turning
- smooth transforms off is faster, but looks worse; turning smooth
- transformations on is slower, but looks better.
+ Primarily used in image based elements to decide if the item should use smooth
+ sampling or not. Smooth sampling is performed using linear interpolation, while
+ non-smooth is performed using nearest neighbor.
- By default smooth transformations are off.
+ In Qt Quick 2.0, this property has minimal impact on performance.
+
+ By default is true.
*/
/*!
@@ -4650,15 +4765,33 @@ void QQuickItem::setFocus(bool focus)
if (d->focus == focus)
return;
- if (d->canvas) {
+ if (d->canvas || d->parentItem) {
// Need to find our nearest focus scope
QQuickItem *scope = parentItem();
- while (scope && !scope->isFocusScope())
+ while (scope && !scope->isFocusScope() && scope->parentItem())
scope = scope->parentItem();
- if (focus)
- QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scope, this);
- else
- QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scope, this);
+ if (d->canvas) {
+ if (focus)
+ QQuickCanvasPrivate::get(d->canvas)->setFocusInScope(scope, this);
+ else
+ QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scope, this);
+ } else {
+ // do the focus changes from setFocusInScope/clearFocusInScope that are
+ // unrelated to a canvas
+ QVarLengthArray<QQuickItem *, 20> changed;
+ QQuickItem *oldSubFocusItem = QQuickItemPrivate::get(scope)->subFocusItem;
+ if (oldSubFocusItem) {
+ QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
+ changed << oldSubFocusItem;
+ }
+ d->updateSubFocusItem(scope, focus);
+
+ d->focus = focus;
+ changed << this;
+ emit focusChanged(focus);
+
+ QQuickCanvasPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ }
} else {
d->focus = focus;
emit focusChanged(focus);
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index f14d60b028..70a8ebc932 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -396,6 +396,7 @@ protected:
const QRectF &oldGeometry);
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void releaseResources();
virtual void updatePolish();
protected Q_SLOTS:
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 03fc66eadb..01e8b4d335 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -450,6 +450,7 @@ public:
QQuickItem**prevDirtyItem;
QQuickCanvas *canvas;
+ int canvasRefCount;
inline QSGContext *sceneGraphContext() const;
QQuickItem *parentItem;
@@ -472,9 +473,13 @@ public:
private:
QQuickItem *focusScope;
};
- void initCanvas(InitializationState *, QQuickCanvas *);
+
+ void refCanvas(QQuickCanvas *);
+ void refCanvas(InitializationState *, QQuickCanvas *);
+ void derefCanvas();
QQuickItem *subFocusItem;
+ void updateSubFocusItem(QQuickItem *scope, bool focus);
QTransform canvasToItemTransform() const;
QTransform itemToCanvasTransform() const;
@@ -856,6 +861,13 @@ QQuickItem::TransformOrigin QQuickItemPrivate::origin() const
return extra.isAllocated()?extra->origin:QQuickItem::Center;
}
+inline void QQuickItemPrivate::refCanvas(QQuickCanvas *c)
+{
+ QQuickItemPrivate::InitializationState initState;
+ initState.clear();
+ refCanvas(&initState, c);
+}
+
QSGTransformNode *QQuickItemPrivate::itemNode()
{
if (!itemNodeInstance) {
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index a1c398eeb6..3e84eb6115 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -927,6 +927,8 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio
void QQuickPathAnimationUpdater::setValue(qreal v)
{
+ v = qMin(qMax(v, (qreal)0.0), (qreal)1.0);;
+
if (interruptStart.isValid()) {
if (reverse)
v = 1 - v;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 50a3216bf0..0d95500860 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1101,9 +1101,9 @@ void QQuickItemView::trackedPositionChanged()
if (d->layoutOrientation() == Qt::Vertical)
endOffset += d->vData.endMargin;
else if (d->isContentFlowReversed())
- endOffset += d->hData.endMargin;
- else
endOffset += d->hData.startMargin;
+ else
+ endOffset += d->hData.endMargin;
trackedPos += endOffset;
trackedEndPos += endOffset;
toItemPos += endOffset;
@@ -1204,12 +1204,11 @@ qreal QQuickItemView::minXExtent() const
return QQuickFlickable::minXExtent();
if (d->hData.minExtentDirty) {
- d->minExtent = -d->startPosition();
+ d->minExtent = -d->startPosition() + d->hData.startMargin;
qreal highlightStart;
qreal highlightEnd;
qreal endPositionFirstItem = 0;
if (d->isContentFlowReversed()) {
- d->minExtent += d->hData.endMargin;
if (d->model && d->model->count())
endPositionFirstItem = d->positionAt(d->model->count()-1);
else if (d->header)
@@ -1222,7 +1221,6 @@ qreal QQuickItemView::minXExtent() const
if (d->minExtent < maxX)
d->minExtent = maxX;
} else {
- d->minExtent += d->hData.startMargin;
endPositionFirstItem = d->endPositionAt(0);
highlightStart = d->highlightRangeStart;
highlightEnd = d->highlightRangeEnd;
@@ -1279,7 +1277,7 @@ qreal QQuickItemView::maxXExtent() const
if (d->isContentFlowReversed()) {
if (d->header)
d->maxExtent -= d->headerSize();
- d->maxExtent -= d->hData.startMargin;
+ d->maxExtent -= d->hData.endMargin;
} else {
if (d->footer)
d->maxExtent -= d->footerSize();
@@ -1314,7 +1312,7 @@ qreal QQuickItemView::xOrigin() const
{
Q_D(const QQuickItemView);
if (d->isContentFlowReversed())
- return -maxXExtent() + d->size() - d->hData.startMargin;
+ return -maxXExtent() + d->size() - d->hData.endMargin;
else
return -minXExtent() + d->hData.startMargin;
}
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 59cb37c15d..f41ba44943 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -61,6 +61,8 @@ QQuickLoaderPrivate::QQuickLoaderPrivate()
QQuickLoaderPrivate::~QQuickLoaderPrivate()
{
+ delete itemContext;
+ itemContext = 0;
delete incubator;
disposeInitialPropertyValues();
}
@@ -79,12 +81,21 @@ void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRec
void QQuickLoaderPrivate::clear()
{
+ Q_Q(QQuickLoader);
disposeInitialPropertyValues();
if (incubator)
incubator->clear();
+ delete itemContext;
+ itemContext = 0;
+
if (loadingFromSource && component) {
+ // disconnect since we deleteLater
+ QObject::disconnect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
+ q, SLOT(_q_sourceLoaded()));
+ QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
+ q, SIGNAL(progressChanged()));
component->deleteLater();
component = 0;
}
@@ -545,6 +556,7 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
QQml_setParent_noEvent(itemContext, obj);
QQml_setParent_noEvent(item, q);
item->setParentItem(q);
+ itemContext = 0;
}
if (initialPropertyValues.IsEmpty())
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 1fa0a90b28..b85a449c51 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1422,6 +1422,9 @@ void QQuickPathView::mouseUngrabEvent()
d->stealMouse = false;
setKeepMouseGrab(false);
d->lastPosTime.invalidate();
+ d->fixOffset();
+ if (!d->tl.isActive())
+ movementEnding();
}
}
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index d7eedd42b6..e232746417 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -398,12 +398,27 @@ void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status)
emit statusChanged();
}
+void QQuickShaderEffect::sourceDestroyed(QObject *object)
+{
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ if (object == source.sourceObject)
+ source.sourceObject = 0;
+ }
+}
+
void QQuickShaderEffect::setSource(const QVariant &var, int index)
{
Q_ASSERT(index >= 0 && index < m_sources.size());
SourceData &source = m_sources[index];
+ if (source.sourceObject) {
+ if (canvas())
+ QQuickItemPrivate::get(source.sourceObject)->derefCanvas();
+ disconnect(source.sourceObject, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
+
source.sourceObject = 0;
if (var.isNull()) {
return;
@@ -425,16 +440,13 @@ void QQuickShaderEffect::setSource(const QVariant &var, int index)
source.sourceObject = item;
if (item) {
- QQuickItemPrivate *d = QQuickItemPrivate::get(item);
// 'item' needs a canvas to get a scene graph node. It usually gets one through its
// parent, but if the source item is "inline" rather than a reference -- i.e.
// "property variant source: Image { }" instead of "property variant source: foo" -- it
// will not get a parent. In those cases, 'item' should get the canvas from 'this'.
- if (!d->parentItem && canvas() && !d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, canvas());
- }
+ if (canvas())
+ QQuickItemPrivate::get(item)->refCanvas(canvas());
+ connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
}
}
@@ -512,6 +524,11 @@ void QQuickShaderEffect::reset()
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
delete source.mapper;
+ if (source.sourceObject) {
+ if (canvas())
+ QQuickItemPrivate::get(source.sourceObject)->derefCanvas();
+ disconnect(source.sourceObject, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
}
m_sources.clear();
m_log.clear();
@@ -817,15 +834,22 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
}
for (int i = 0; i < oldTextures.size(); ++i) {
QSGTextureProvider *t = oldTextures.at(i).second;
- if (t)
+ if (t) {
disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
}
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
QSGTextureProvider *t = source.sourceObject ? source.sourceObject->textureProvider() : 0;
textures.append(qMakePair(source.name, t));
- if (t)
- connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ if (t) {
+ Q_ASSERT_X(t->thread() == QThread::currentThread(),
+ "QQuickShaderEffect::updatePaintNode",
+ "Texture provider must belong to the rendering thread");
+ connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ connect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
}
material->setUniforms(values);
material->setTextureProviders(textures);
@@ -840,12 +864,15 @@ void QQuickShaderEffect::itemChange(ItemChange change, const ItemChangeData &val
{
if (change == QQuickItem::ItemSceneChange) {
// See comment in QQuickShaderEffect::setSource().
- for (int i = 0; i < m_sources.size(); ++i) {
- QQuickItemPrivate *d = QQuickItemPrivate::get(m_sources.at(i).sourceObject);
- if (!d->parentItem && value.canvas != d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, value.canvas);
+ if (value.canvas) {
+ for (int i = 0; i < m_sources.size(); ++i) {
+ if (m_sources.at(i).sourceObject)
+ QQuickItemPrivate::get(m_sources.at(i).sourceObject)->refCanvas(value.canvas);
+ }
+ } else {
+ for (int i = 0; i < m_sources.size(); ++i) {
+ if (m_sources.at(i).sourceObject)
+ QQuickItemPrivate::get(m_sources.at(i).sourceObject)->derefCanvas();
}
}
}
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 4475c22b28..db1e4e78c1 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -133,6 +133,7 @@ private Q_SLOTS:
void updateData();
void updateGeometry();
void updateLogAndStatus(const QString &log, int status);
+ void sourceDestroyed(QObject *object);
private:
friend class QQuickCustomMaterialShader;
@@ -156,7 +157,7 @@ private:
struct SourceData
{
QSignalMapper *mapper;
- QPointer<QQuickItem> sourceObject;
+ QQuickItem *sourceObject;
QByteArray name;
};
QVector<SourceData> m_sources;
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index ae61ad940d..c4b91844e0 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -376,6 +376,14 @@ void QQuickShaderEffectMaterial::updateTextures() const
}
}
+void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
+{
+ for (int i = 0; i < m_textures.size(); ++i) {
+ if (provider == m_textures.at(i).second)
+ m_textures[i].second = 0;
+ }
+}
+
QQuickShaderEffectNode::QQuickShaderEffectNode()
: m_material(this)
@@ -397,6 +405,12 @@ void QQuickShaderEffectNode::markDirtyTexture()
markDirty(DirtyMaterial);
}
+void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object)
+{
+ Q_ASSERT(qobject_cast<QSGTextureProvider *>(object));
+ m_material.invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
+}
+
void QQuickShaderEffectNode::preprocess()
{
Q_ASSERT(material());
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h
index fc47f626e1..e22d2de9e2 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickshadereffectnode_p.h
@@ -102,6 +102,7 @@ public:
void setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures);
const QVector<QPair<QByteArray, QSGTextureProvider *> > &textureProviders() const;
void updateTextures() const;
+ void invalidateTextureProvider(QSGTextureProvider *provider);
protected:
friend class QQuickCustomMaterialShader;
@@ -143,6 +144,7 @@ Q_SIGNALS:
private Q_SLOTS:
void markDirtyTexture();
+ void textureProviderDestroyed(QObject *object);
private:
QQuickShaderEffectMaterial m_material;
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 33776be712..c55b1ca7f5 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -54,6 +54,39 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
+namespace
+{
+ class BindableFbo : public QSGBindable
+ {
+ public:
+ BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil);
+ virtual ~BindableFbo();
+ virtual void bind() const;
+ private:
+ QOpenGLFramebufferObject *m_fbo;
+ QSGDepthStencilBuffer *m_depthStencil;
+ };
+
+ BindableFbo::BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil)
+ : m_fbo(fbo)
+ , m_depthStencil(depthStencil)
+ {
+ }
+
+ BindableFbo::~BindableFbo()
+ {
+ if (m_depthStencil)
+ m_depthStencil->detach();
+ }
+
+ void BindableFbo::bind() const
+ {
+ m_fbo->bind();
+ if (m_depthStencil)
+ m_depthStencil->attach();
+ }
+}
+
class QQuickShaderEffectSourceTextureProvider : public QSGTextureProvider
{
Q_OBJECT
@@ -239,6 +272,7 @@ void QQuickShaderEffectTexture::grab()
delete m_fbo;
delete m_secondaryFbo;
m_fbo = m_secondaryFbo = 0;
+ m_depthStencilBuffer.clear();
m_dirtyTexture = false;
if (m_grab)
emit scheduledUpdateCompleted();
@@ -272,13 +306,12 @@ void QQuickShaderEffectTexture::grab()
delete m_secondaryFbo;
QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setInternalTextureFormat(m_format);
format.setSamples(8);
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
+ m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setInternalTextureFormat(m_format);
format.setMipmap(m_mipmap);
if (m_recursive) {
@@ -287,6 +320,7 @@ void QQuickShaderEffectTexture::grab()
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
updateBindOptions(true);
+ m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
delete m_fbo;
delete m_secondaryFbo;
@@ -294,6 +328,7 @@ void QQuickShaderEffectTexture::grab()
m_secondaryFbo = 0;
glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
updateBindOptions(true);
+ m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo);
}
}
}
@@ -336,7 +371,7 @@ void QQuickShaderEffectTexture::grab()
m_renderer->setClearColor(Qt::transparent);
if (m_multisampling) {
- m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo));
+ m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
if (deleteFboLater) {
delete m_fbo;
@@ -354,7 +389,7 @@ void QQuickShaderEffectTexture::grab()
QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r);
} else {
if (m_recursive) {
- m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo));
+ m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
if (deleteFboLater) {
delete m_fbo;
@@ -368,7 +403,7 @@ void QQuickShaderEffectTexture::grab()
}
qSwap(m_fbo, m_secondaryFbo);
} else {
- m_renderer->renderScene(QSGBindableFbo(m_fbo));
+ m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data()));
}
}
@@ -504,6 +539,8 @@ QQuickShaderEffectSource::~QQuickShaderEffectSource()
QQuickItemPrivate *sd = QQuickItemPrivate::get(m_sourceItem);
sd->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
sd->derefFromEffectItem(m_hideSource);
+ if (canvas())
+ sd->derefCanvas();
}
}
@@ -599,6 +636,9 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem);
d->derefFromEffectItem(m_hideSource);
d->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ disconnect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
+ if (canvas())
+ d->derefCanvas();
}
m_sourceItem = item;
@@ -608,18 +648,25 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
// parent, but if the source item is "inline" rather than a reference -- i.e.
// "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
// In those cases, 'item' should get the canvas from 'this'.
- if (!d->parentItem && canvas() && !d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, canvas());
- }
+ if (canvas())
+ d->refCanvas(canvas());
d->refFromEffectItem(m_hideSource);
d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
}
update();
emit sourceItemChanged();
}
+void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
+{
+ Q_ASSERT(item == m_sourceItem);
+ m_sourceItem = 0;
+ update();
+ emit sourceItemChanged();
+}
+
+
/*!
\qmlproperty rect ShaderEffectSource::sourceRect
@@ -841,22 +888,35 @@ static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::W
}
+void QQuickShaderEffectSource::releaseResources()
+{
+ if (m_texture) {
+ m_texture->deleteLater();
+ m_texture = 0;
+ }
+ if (m_provider) {
+ m_provider->deleteLater();
+ m_provider = 0;
+ }
+}
+
QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
if (!m_sourceItem || m_sourceItem->width() == 0 || m_sourceItem->height() == 0) {
+ if (m_texture)
+ m_texture->setItem(0);
delete oldNode;
return 0;
}
ensureTexture();
- QQuickShaderEffectTexture *tex = qobject_cast<QQuickShaderEffectTexture *>(m_texture);
- tex->setLive(m_live);
- tex->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
+ m_texture->setLive(m_live);
+ m_texture->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0
? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
: m_sourceRect;
- tex->setRect(sourceRect);
+ m_texture->setRect(sourceRect);
QSize textureSize = m_textureSize.isEmpty()
? QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())))
: m_textureSize;
@@ -869,13 +929,13 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
while (textureSize.height() < minTextureSize.height())
textureSize.rheight() *= 2;
- tex->setSize(textureSize);
- tex->setRecursive(m_recursive);
- tex->setFormat(GLenum(m_format));
- tex->setHasMipmaps(m_mipmap);
+ m_texture->setSize(textureSize);
+ m_texture->setRecursive(m_recursive);
+ m_texture->setFormat(GLenum(m_format));
+ m_texture->setHasMipmaps(m_mipmap);
if (m_grab)
- tex->scheduleUpdate();
+ m_texture->scheduleUpdate();
m_grab = false;
QSGTexture::Filtering filtering = QQuickItemPrivate::get(this)->smooth
@@ -924,12 +984,10 @@ void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeDat
{
if (change == QQuickItem::ItemSceneChange && m_sourceItem) {
// See comment in QQuickShaderEffectSource::setSourceItem().
- QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem);
- if (!d->parentItem && value.canvas != d->canvas) {
- QQuickItemPrivate::InitializationState initState;
- initState.clear();
- d->initCanvas(&initState, value.canvas);
- }
+ if (value.canvas)
+ QQuickItemPrivate::get(m_sourceItem)->refCanvas(value.canvas);
+ else
+ QQuickItemPrivate::get(m_sourceItem)->derefCanvas();
}
QQuickItem::itemChange(change, value);
}
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 793e89cd69..0853394339 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -136,6 +136,7 @@ private:
QSGRenderer *m_renderer;
QOpenGLFramebufferObject *m_fbo;
QOpenGLFramebufferObject *m_secondaryFbo;
+ QSharedPointer<QSGDepthStencilBuffer> m_depthStencilBuffer;
#ifdef QSG_DEBUG_FBO_OVERLAY
QSGRectangleNode *m_debugOverlay;
@@ -228,7 +229,11 @@ Q_SIGNALS:
void scheduledUpdateCompleted();
+private Q_SLOTS:
+ void sourceItemDestroyed(QObject *item);
+
protected:
+ virtual void releaseResources();
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
virtual void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect);
@@ -240,7 +245,7 @@ private:
QQuickShaderEffectSourceTextureProvider *m_provider;
QQuickShaderEffectTexture *m_texture;
WrapMode m_wrapMode;
- QPointer<QQuickItem> m_sourceItem;
+ QQuickItem *m_sourceItem;
QRectF m_sourceRect;
QSize m_textureSize;
Format m_format;
diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp
index e0535ed77e..724bf8fef1 100644
--- a/src/quick/items/qquicksprite.cpp
+++ b/src/quick/items/qquicksprite.cpp
@@ -248,12 +248,14 @@ int QQuickSprite::variedDuration() const //Deals with precedence when multiple d
+ (m_frameDurationVariation * ((qreal)qrand()/RAND_MAX) * 2)
- m_frameDurationVariation;
return qMax(0, m_frames * mspf);
- }
- qWarning() << "Sprite::duration is changing meaning to the full animation duration.";
- qWarning() << "Use Sprite::frameDuration for the old meaning, of per frame duration.";
- qWarning() << "As an interim measure, duration/durationVariation means the same as frameDuration/frameDurationVariation, and you'll get this warning spewed out everywhere to movtivate you.";
+ } else if (duration() >= 0) {
+ qWarning() << "Sprite::duration is changing meaning to the full animation duration.";
+ qWarning() << "Use Sprite::frameDuration for the old meaning, of per frame duration.";
+ qWarning() << "As an interim measure, duration/durationVariation means the same as frameDuration/frameDurationVariation, and you'll get this warning spewed out everywhere to motivate you.";
//Note that the spammyness is due to this being the best location to detect, but also called once each animation loop
- return QQuickStochasticState::variedDuration() * m_frames;
+ return QQuickStochasticState::variedDuration() * m_frames;
+ }
+ return 1000; //When nothing set
}
void QQuickSprite::startImageLoading()
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index 1c35688c29..d4ddbc400d 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -411,9 +411,9 @@ QImage QQuickSpriteEngine::assembledImage()
int frameWidth = state->m_frameWidth;
int frameHeight = state->m_frameHeight;
if (img.height() == frameHeight && img.width() < maxSize){//Simple case
- p.drawImage(0,y,img);
+ p.drawImage(0,y,img.copy(state->m_frameX,0,state->m_frames * frameWidth, frameHeight));
+ state->m_rowStartX = 0;
state->m_rowY = y;
- state->m_rowStartX = state->m_frameX;//In case it was offset, but we took the simple route of not chopping out the other bits
y += frameHeight;
}else{//Chopping up image case
state->m_framesPerRow = image.width()/frameWidth;
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index 3763509462..00cefbfbc0 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -70,7 +70,7 @@ class Q_AUTOTEST_EXPORT QQuickStochasticState : public QObject //Currently for i
public:
QQuickStochasticState(QObject* parent = 0)
: QObject(parent)
- , m_duration(1000)
+ , m_duration(-1)
, m_durationVariation(0)
, m_randomStart(false)
{
diff --git a/src/quick/items/qquickspriteimage.cpp b/src/quick/items/qquickspriteimage.cpp
index 6edb3ad8c3..2a151d02a8 100644
--- a/src/quick/items/qquickspriteimage.cpp
+++ b/src/quick/items/qquickspriteimage.cpp
@@ -261,7 +261,7 @@ struct SpriteVertices {
The sprite or sprites to draw. Sprites will be scaled to the size of this element.
*/
-//TODO: Implicitly size element to size of first sprite?
+//TODO: Implicitly size element to size of first sprite? or currentSprite?
QQuickSpriteImage::QQuickSpriteImage(QQuickItem *parent) :
QQuickItem(parent)
, m_node(0)
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 9f22dfdd08..d7303352c5 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -421,6 +421,10 @@ void QQuickTextPrivate::updateSize()
//setup instance of QTextLayout for all cases other than richtext
if (!richText) {
QRectF textRect = setupTextLayout(&naturalWidth);
+
+ if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect if it is.
+
layedOutTextRect = textRect;
size = textRect.size();
dy -= size.height();
@@ -443,7 +447,13 @@ void QQuickTextPrivate::updateSize()
if (requireImplicitWidth && q->widthValid()) {
extra->doc->setTextWidth(-1);
naturalWidth = extra->doc->idealWidth();
+ const bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(naturalWidth);
+ internalWidthUpdate = wasInLayout;
}
+ if (internalWidthUpdate)
+ return;
if (wrapMode != QQuickText::NoWrap && q->widthValid())
extra->doc->setTextWidth(q->width());
else
@@ -468,8 +478,6 @@ void QQuickTextPrivate::updateSize()
qreal iWidth = -1;
if (!q->widthValid())
iWidth = size.width();
- else if (requireImplicitWidth)
- iWidth = naturalWidth;
if (iWidth > -1)
q->setImplicitSize(iWidth, size.height());
internalWidthUpdate = false;
@@ -697,6 +705,11 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
layout.endLayout();
*naturalWidth = layout.maximumWidth();
layout.clearLayout();
+
+ bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(*naturalWidth);
+ internalWidthUpdate = wasInLayout;
}
QFontMetrics fm(font);
@@ -704,7 +717,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
return QRect(0, 0, 0, height);
}
- const qreal lineWidth = q->widthValid() ? q->width() : FLT_MAX;
+ qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
const bool customLayout = isLineLaidOutConnected();
@@ -735,6 +748,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
QTextLine line;
int visibleCount = 0;
bool elide;
+ bool widthChanged;
qreal height = 0;
QString elideText;
bool once = true;
@@ -755,13 +769,14 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
scaledFont.setPointSize(scaledFontSize);
layout.setFont(scaledFont);
}
- layout.beginLayout();
+ layout.beginLayout();
bool wrapped = false;
bool truncateHeight = false;
truncated = false;
elide = false;
+ widthChanged = false;
int characterCount = 0;
int unwrappedLineCount = 1;
int maxLineCount = maximumLineCount();
@@ -864,7 +879,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
br = br.united(line.naturalTextRect());
line = nextLine;
}
-
layout.endLayout();
br.moveTop(0);
@@ -886,8 +900,21 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
if (!line.isValid())
break;
}
+
*naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth());
}
+
+ bool wasInLayout = internalWidthUpdate;
+ internalWidthUpdate = true;
+ q->setImplicitWidth(*naturalWidth);
+ internalWidthUpdate = wasInLayout;
+
+ const qreal oldWidth = lineWidth;
+ lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
+ if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit)) {
+ widthChanged = true;
+ continue;
+ }
}
// If the next needs to be elided and there's an abbreviated string available
@@ -911,32 +938,36 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
largeFont = scaledFontSize - 1;
- scaledFontSize = (smallFont + largeFont) / 2;
if (smallFont > largeFont)
break;
+ scaledFontSize = (smallFont + largeFont) / 2;
+ if (pixelSize)
+ scaledFont.setPixelSize(scaledFontSize);
+ else
+ scaledFont.setPointSize(scaledFontSize);
continue;
} else if (!verticalFit) {
smallFont = scaledFontSize;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont == largeFont)
break;
+ scaledFontSize = (smallFont + largeFont + 1) / 2;
}
}
if (verticalFit) {
if (truncateHeight || unelidedRect.height() > maxHeight) {
largeFont = scaledFontSize - 1;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont > largeFont)
break;
+ scaledFontSize = (smallFont + largeFont) / 2;
+
} else {
smallFont = scaledFontSize;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
if (smallFont == largeFont)
break;
+ scaledFontSize = (smallFont + largeFont + 1) / 2;
}
}
-
}
if (eos != multilengthEos)
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 9a61312910..1846d03b9b 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -531,29 +531,12 @@ void QQuickTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition,
if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
return;
- if (wordSelectionEnabled) {
- if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
- cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
- setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
- } else {
- cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
- setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
- }
+ if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
+ cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
+ setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
} else {
- // keep the already selected word even when moving to the left
- // (#39164)
- if (suggestedNewPosition < selectedWordOnDoubleClick.position())
- cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
- else
- cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
-
- const qreal differenceToStart = mouseXPosition - wordStartX;
- const qreal differenceToEnd = wordEndX - mouseXPosition;
-
- if (differenceToStart < differenceToEnd)
- setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
- else
- setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
+ cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
+ setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
}
if (interactionFlags & Qt::TextSelectableByMouse) {
@@ -594,13 +577,6 @@ void QQuickTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition
}
}
-void QQuickTextControlPrivate::_q_deleteSelected()
-{
- if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
- return;
- cursor.removeSelectedText();
-}
-
void QQuickTextControl::undo()
{
Q_D(QQuickTextControl);
@@ -690,14 +666,6 @@ void QQuickTextControl::paste(QClipboard::Mode mode)
}
#endif
-void QQuickTextControl::clear()
-{
- Q_D(QQuickTextControl);
- // clears and sets empty content
- d->setContent();
-}
-
-
void QQuickTextControl::selectAll()
{
Q_D(QQuickTextControl);
@@ -1527,13 +1495,6 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property) cons
}
}
-void QQuickTextControl::setFocus(bool focus, Qt::FocusReason reason)
-{
- QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
- reason);
- processEvent(&ev);
-}
-
void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
{
Q_Q(QQuickTextControl);
@@ -1555,31 +1516,6 @@ void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
}
}
-QString QQuickTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
-{
- if (anchorCursor.hasSelection()) {
- QTextCursor cursor = anchorCursor;
- if (cursor.selectionStart() != cursor.position())
- cursor.setPosition(cursor.selectionStart());
- cursor.movePosition(QTextCursor::NextCharacter);
- QTextCharFormat fmt = cursor.charFormat();
- if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
- return fmt.stringProperty(QTextFormat::AnchorHref);
- }
- return QString();
-}
-
-QTextCursor QQuickTextControl::cursorForPosition(const QPointF &pos) const
-{
- Q_D(const QQuickTextControl);
- int cursorPos = hitTest(pos, Qt::FuzzyHit);
- if (cursorPos == -1)
- cursorPos = 0;
- QTextCursor c(d->doc);
- c.setPosition(cursorPos);
- return c;
-}
-
QRectF QQuickTextControl::cursorRect(const QTextCursor &cursor) const
{
Q_D(const QQuickTextControl);
@@ -1609,23 +1545,6 @@ QString QQuickTextControl::anchorAt(const QPointF &pos) const
return d->doc->documentLayout()->anchorAt(pos);
}
-QString QQuickTextControl::anchorAtCursor() const
-{
- Q_D(const QQuickTextControl);
-
- return d->anchorForCursor(d->cursor);
-}
-
-int QQuickTextControl::cursorWidth() const
-{
-#ifndef QT_NO_PROPERTIES
- Q_D(const QQuickTextControl);
- return d->doc->documentLayout()->property("cursorWidth").toInt();
-#else
- return 1;
-#endif
-}
-
void QQuickTextControl::setCursorWidth(int width)
{
Q_D(QQuickTextControl);
@@ -1639,36 +1558,12 @@ void QQuickTextControl::setCursorWidth(int width)
d->repaintCursor();
}
-bool QQuickTextControl::acceptRichText() const
-{
- Q_D(const QQuickTextControl);
- return d->acceptRichText;
-}
-
void QQuickTextControl::setAcceptRichText(bool accept)
{
Q_D(QQuickTextControl);
d->acceptRichText = accept;
}
-void QQuickTextControl::setTextWidth(qreal width)
-{
- Q_D(QQuickTextControl);
- d->doc->setTextWidth(width);
-}
-
-qreal QQuickTextControl::textWidth() const
-{
- Q_D(const QQuickTextControl);
- return d->doc->textWidth();
-}
-
-QSizeF QQuickTextControl::size() const
-{
- Q_D(const QQuickTextControl);
- return d->doc->size();
-}
-
void QQuickTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
{
Q_D(QQuickTextControl);
@@ -1700,24 +1595,12 @@ void QQuickTextControl::setCursorIsFocusIndicator(bool b)
d->repaintCursor();
}
-bool QQuickTextControl::cursorIsFocusIndicator() const
-{
- Q_D(const QQuickTextControl);
- return d->cursorIsFocusIndicator;
-}
-
void QQuickTextControl::setWordSelectionEnabled(bool enabled)
{
Q_D(QQuickTextControl);
d->wordSelectionEnabled = enabled;
}
-bool QQuickTextControl::isWordSelectionEnabled() const
-{
- Q_D(const QQuickTextControl);
- return d->wordSelectionEnabled;
-}
-
QMimeData *QQuickTextControl::createMimeDataFromSelection() const
{
Q_D(const QQuickTextControl);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 97ecdc4c6e..9e3fc90eb1 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -80,12 +80,6 @@ class Q_AUTOTEST_EXPORT QQuickTextControl : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickTextControl)
-#ifndef QT_NO_TEXTHTMLPARSER
- Q_PROPERTY(QString html READ toHtml WRITE setHtml NOTIFY textChanged USER true)
-#endif
- Q_PROPERTY(bool acceptRichText READ acceptRichText WRITE setAcceptRichText)
- Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
- Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
public:
explicit QQuickTextControl(QTextDocument *doc, QObject *parent = 0);
virtual ~QQuickTextControl();
@@ -104,7 +98,6 @@ public:
QString toHtml() const;
#endif
- QTextCursor cursorForPosition(const QPointF &pos) const;
QRectF cursorRect(const QTextCursor &cursor) const;
QRectF cursorRect() const;
QRectF selectionRect(const QTextCursor &cursor) const;
@@ -112,26 +105,15 @@ public:
QString anchorAt(const QPointF &pos) const;
- QString anchorAtCursor() const;
-
- int cursorWidth() const;
void setCursorWidth(int width);
- bool acceptRichText() const;
void setAcceptRichText(bool accept);
- void setTextWidth(qreal width);
- qreal textWidth() const;
- QSizeF size() const;
-
void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
bool canPaste() const;
void setCursorIsFocusIndicator(bool b);
- bool cursorIsFocusIndicator() const;
-
- bool isWordSelectionEnabled() const;
void setWordSelectionEnabled(bool enabled);
virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;
@@ -151,7 +133,6 @@ public Q_SLOTS:
void undo();
void redo();
- void clear();
void selectAll();
Q_SIGNALS:
@@ -175,9 +156,6 @@ public:
virtual void processEvent(QEvent *e, const QMatrix &matrix);
void processEvent(QEvent *e, const QPointF &coordinateOffset = QPointF());
- // control methods
- void setFocus(bool focus, Qt::FocusReason = Qt::OtherFocusReason);
-
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
virtual QMimeData *createMimeDataFromSelection() const;
@@ -195,7 +173,6 @@ private:
Q_DISABLE_COPY(QQuickTextControl)
Q_PRIVATE_SLOT(d_func(), void _q_updateCurrentCharFormatAndSelection())
Q_PRIVATE_SLOT(d_func(), void _q_emitCursorPosChanged(const QTextCursor &))
- Q_PRIVATE_SLOT(d_func(), void _q_deleteSelected())
Q_PRIVATE_SLOT(d_func(), void _q_updateBlock(const QTextBlock &))
Q_PRIVATE_SLOT(d_func(), void _q_documentLayoutChanged())
};
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index 44bc00221b..9d776ce46b 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -106,8 +106,6 @@ public:
void extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition);
void extendBlockwiseSelection(int suggestedNewPosition);
- void _q_deleteSelected();
-
void _q_setCursorAfterUndoRedo(int undoPosition, int charsAdded, int charsRemoved);
QRectF cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const;
@@ -116,8 +114,6 @@ public:
inline QRectF selectionRect() const
{ return selectionRect(this->cursor); }
- QString anchorForCursor(const QTextCursor &anchor) const;
-
void keyPressEvent(QKeyEvent *e);
void mousePressEvent(QMouseEvent *event, const QPointF &pos);
void mouseMoveEvent(QMouseEvent *event, const QPointF &pos);
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 5456d3523a..4fa5233b9a 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1143,7 +1143,8 @@ void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry)
{
- if (newGeometry.width() != oldGeometry.width())
+ Q_D(QQuickTextEdit);
+ if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap && !d->inLayout)
updateSize();
QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
}
@@ -1477,6 +1478,7 @@ Handles the given mouse \a event.
void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
if (d->focusOnPress){
bool hadActiveFocus = hasActiveFocus();
forceActiveFocus();
@@ -1484,7 +1486,6 @@ void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
openSoftwareInputPanel();
}
- d->control->processEvent(event, QPointF(0, -d->yoff));
if (!event->isAccepted())
QQuickImplicitSizeItem::mousePressEvent(event);
}
@@ -1857,6 +1858,13 @@ void QQuickTextEdit::updateSize()
if (d->requireImplicitWidth) {
d->document->setTextWidth(-1);
naturalWidth = d->document->idealWidth();
+
+ const bool wasInLayout = d->inLayout;
+ d->inLayout = true;
+ setImplicitWidth(naturalWidth);
+ d->inLayout = wasInLayout;
+ if (d->inLayout) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect.
}
if (d->document->textWidth() != width())
d->document->setTextWidth(width());
@@ -1888,11 +1896,11 @@ void QQuickTextEdit::updateSize()
d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
// ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
qreal iWidth = -1;
- if (!widthValid())
+ if (!widthValid() && !d->requireImplicitWidth)
iWidth = newWidth;
- else if (d->requireImplicitWidth)
- iWidth = naturalWidth;
+
qreal newHeight = d->document->isEmpty() ? fm.height() : d->document->size().height();
+
if (iWidth > -1)
setImplicitSize(iWidth, newHeight);
else
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index 055b5c7929..f0a35d5266 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -78,7 +78,7 @@ public:
, documentDirty(true), dirty(false), richText(false), cursorVisible(false)
, focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
, selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
- , rightToLeftText(false), textCached(false)
+ , rightToLeftText(false), textCached(false), inLayout(false)
{
}
@@ -144,6 +144,7 @@ public:
bool hAlignImplicit:1;
bool rightToLeftText:1;
bool textCached:1;
+ bool inLayout:1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 0b21d6b169..94856b63ab 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1444,13 +1444,9 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event)
d->pressPos = event->localPos();
- if (d->focusOnPress) {
- bool hadActiveFocus = hasActiveFocus();
- forceActiveFocus();
- // re-open input panel on press if already focused
- if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
- openSoftwareInputPanel();
- }
+ if (d->sendMouseEventToInputContext(event))
+ return;
+
if (d->selectByMouse) {
setKeepMouseGrab(false);
d->selectPressed = true;
@@ -1463,12 +1459,18 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event)
}
}
- if (d->sendMouseEventToInputContext(event))
- return;
-
bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
int cursor = d->positionAt(event->localPos());
d->moveCursor(cursor, mark);
+
+ if (d->focusOnPress) {
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ // re-open input panel on press if already focused
+ if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
+ openSoftwareInputPanel();
+ }
+
event->setAccepted(true);
}
@@ -1602,9 +1604,11 @@ void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry)
{
Q_D(QQuickTextInput);
- if (newGeometry.width() != oldGeometry.width())
- d->updateLayout();
- updateCursorRectangle();
+ if (!d->inLayout) {
+ if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
+ d->updateLayout();
+ updateCursorRectangle();
+ }
QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
}
@@ -1614,14 +1618,19 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
const int preeditLength = m_textLayout.preeditAreaText().length();
const qreal width = qMax<qreal>(0, q->width());
- qreal widthUsed = currentLine.isValid() ? currentLine.naturalTextWidth() : 0;
+ qreal cix = 0;
+ qreal widthUsed = 0;
+ if (currentLine.isValid()) {
+ cix = currentLine.cursorToX(m_cursor + preeditLength);
+ const qreal cursorWidth = cix >= 0 ? cix : width - cix;
+ widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
+ }
int previousScroll = hscroll;
if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
hscroll = 0;
} else {
Q_ASSERT(currentLine.isValid());
- qreal cix = currentLine.cursorToX(m_cursor + preeditLength);
if (cix - hscroll >= width) {
// text doesn't fit, cursor is to the right of br (scroll right)
hscroll = cix - width;
@@ -1632,6 +1641,10 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
// text doesn't fit, text document is to the left of br; align
// right
hscroll = widthUsed - width;
+ } else if (width - hscroll > widthUsed) {
+ // text doesn't fit, text document is to the right of br; align
+ // left
+ hscroll = width - widthUsed;
}
if (preeditLength > 0) {
// check to ensure long pre-edit text doesn't push the cursor
@@ -2688,6 +2701,38 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
}
}
+qreal QQuickTextInputPrivate::getImplicitWidth() const
+{
+ Q_Q(const QQuickTextInput);
+ if (!requireImplicitWidth) {
+ QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
+ d->requireImplicitWidth = true;
+
+ if (q->isComponentComplete()) {
+ // One time cost, only incurred if implicitWidth is first requested after
+ // componentComplete.
+ QTextLayout layout(m_text);
+
+ QTextOption option = m_textLayout.textOption();
+ option.setTextDirection(m_layoutDirection);
+ option.setFlags(QTextOption::IncludeTrailingSpaces);
+ option.setWrapMode(QTextOption::WrapMode(wrapMode));
+ option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
+ layout.setTextOption(option);
+ layout.setFont(font);
+ layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
+ layout.beginLayout();
+
+ QTextLine line = layout.createLine();
+ line.setLineWidth(INT_MAX);
+ d->implicitWidth = qCeil(line.naturalTextWidth());
+
+ layout.endLayout();
+ }
+ }
+ return implicitWidth;
+}
+
void QQuickTextInputPrivate::updateLayout()
{
Q_Q(QQuickTextInput);
@@ -2699,7 +2744,6 @@ void QQuickTextInputPrivate::updateLayout()
QTextOption option = m_textLayout.textOption();
option.setTextDirection(layoutDirection());
- option.setFlags(QTextOption::IncludeTrailingSpaces);
option.setWrapMode(QTextOption::WrapMode(wrapMode));
option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
m_textLayout.setTextOption(option);
@@ -2708,9 +2752,17 @@ void QQuickTextInputPrivate::updateLayout()
boundingRect = QRectF();
m_textLayout.beginLayout();
QTextLine line = m_textLayout.createLine();
+ if (requireImplicitWidth) {
+ line.setLineWidth(INT_MAX);
+ const bool wasInLayout = inLayout;
+ inLayout = true;
+ q->setImplicitWidth(qCeil(line.naturalTextWidth()));
+ inLayout = wasInLayout;
+ if (inLayout) // probably the result of a binding loop, but by letting it
+ return; // get this far we'll get a warning to that effect.
+ }
qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
qreal height = 0;
- QTextLine firstLine = line;
do {
line.setLineWidth(lineWidth);
line.setPosition(QPointF(line.position().x(), height));
@@ -2728,7 +2780,11 @@ void QQuickTextInputPrivate::updateLayout()
updateType = UpdatePaintNode;
q->update();
- q->setImplicitSize(boundingRect.width(), boundingRect.height());
+
+ if (!requireImplicitWidth && !q->widthValid())
+ q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
+ else
+ q->setImplicitHeight(qCeil(boundingRect.height()));
if (previousRect != boundingRect)
emit q->contentSizeChanged();
@@ -3261,7 +3317,14 @@ void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool e
m_textDirty = (oldText != m_text);
bool changed = finishChange(-1, true, edited);
+#ifdef QT_NO_ACCESSIBILITY
Q_UNUSED(changed)
+#else
+ if (changed) {
+ QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
@@ -3885,6 +3948,11 @@ bool QQuickTextInputPrivate::emitCursorPositionChanged()
}
}
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessibleTextCursorEvent ev(q, m_cursor);
+ QAccessible::updateAccessibility(&ev);
+#endif
+
return true;
}
return false;
@@ -3964,12 +4032,10 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
}
#ifndef QT_NO_SHORTCUT
else if (event == QKeySequence::Undo) {
- if (!m_readOnly)
- q->undo();
+ q->undo();
}
else if (event == QKeySequence::Redo) {
- if (!m_readOnly)
- q->redo();
+ q->redo();
}
else if (event == QKeySequence::SelectAll) {
selectAll();
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index bb00600661..165155acd0 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -125,6 +125,8 @@ public:
, m_acceptableInput(1)
, m_blinkStatus(0)
, m_passwordEchoEditing(false)
+ , inLayout(false)
+ , requireImplicitWidth(false)
{
}
@@ -256,7 +258,8 @@ public:
bool m_acceptableInput : 1;
bool m_blinkStatus : 1;
bool m_passwordEchoEditing : 1;
-
+ bool inLayout:1;
+ bool requireImplicitWidth:1;
static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
return t->d_func();
@@ -404,6 +407,8 @@ public:
void updateLayout();
+ qreal getImplicitWidth() const;
+
private:
void removeSelectedText();
void internalSetText(const QString &txt, int pos = -1, bool edited = true);
diff --git a/src/quick/items/qquickvisualadaptormodel.cpp b/src/quick/items/qquickvisualadaptormodel.cpp
index 622adf4ce9..cd9db7235b 100644
--- a/src/quick/items/qquickvisualadaptormodel.cpp
+++ b/src/quick/items/qquickvisualadaptormodel.cpp
@@ -65,7 +65,8 @@ public:
}
VDMDelegateDataType(const VDMDelegateDataType &type)
- : metaObject(0)
+ : QQmlRefCount()
+ , metaObject(0)
, propertyCache(0)
, propertyOffset(type.propertyOffset)
, signalOffset(type.signalOffset)
diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp
index 64eb2bf53b..61c2ef24b4 100644
--- a/src/quick/items/qquickwindowmanager.cpp
+++ b/src/quick/items/qquickwindowmanager.cpp
@@ -228,7 +228,7 @@ public slots:
private:
void handleAddedWindows();
void handleAddedWindow(QQuickCanvas *canvas);
- void handleRemovedWindows();
+ void handleRemovedWindows(bool clearGLContext = true);
QSGContext *sg;
QOpenGLContext *gl;
@@ -475,7 +475,7 @@ void QQuickRenderThreadSingleContextWindowManager::hide(QQuickCanvas *canvas)
/*!
Called on Render Thread
*/
-void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows()
+void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows(bool clearGLContext)
{
#ifdef THREAD_DEBUG
printf(" RenderThread: about to remove %d\n", m_removed_windows.size());
@@ -496,7 +496,7 @@ void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows()
// If a window is removed because it has been hidden it will take with it
// the gl context (at least on Mac) if bound, so disconnect the gl context
// from anything
- if (removedAnything)
+ if (removedAnything && clearGLContext)
gl->doneCurrent();
}
@@ -755,7 +755,7 @@ void QQuickRenderThreadSingleContextWindowManager::run()
#endif
m_removed_windows << m_rendered_windows.keys();
- handleRemovedWindows();
+ handleRemovedWindows(false);
sg->invalidate();