aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/accessible
diff options
context:
space:
mode:
authorJan Arve Saether <jan-arve.saether@digia.com>2014-09-10 13:10:19 +0200
committerJan Arve Sæther <jan-arve.saether@theqtcompany.com>2014-10-21 08:05:08 +0200
commitdb16f3e56e73846bc70eab08869dfb57706db2bf (patch)
tree88326bc82b0e38caad05126ae81ceae2a8539fbb /src/quick/accessible
parentd6661ca409ebf1e4a2fa21fa4f084f63f70052e3 (diff)
Improve hit testing so that it works better with ignored items
The hit testing won't work very well with the upcoming patch that changes which items that can be ignored. (basically it doesn't consider the isAccessible flag, so childAt_helper might return a node that was supposed to be ignored) Earlier this was a sensible optimization in order to avoid too many heap allocations and deallocations of interfaces, but these are cheap now, so we can do it the do it the 'proper way' (i.e. before this patch we didn't respect the a11y hierarchy as given by QAccessibleInterface child() and parent(). This also uses the QAccessibleInterface::rect() directly now instead of using the itemScreenRect() function, which was shared between QAccessibleQuickWindow and QAccessibleQuickItem. Since this changes the order of child interfaces to paint order (i.e. second child interface is on top of first child interface), we need to ensure that we hit test child interfaces in the correct order. They should now always be processed with the last interface first, and then return as soon as something is hit. Change-Id: Ie951fc3b48b7affd9f7e98687a1cbbe008857d2a Reviewed-by: Frederik Gladhorn <frederik.gladhorn@theqtcompany.com>
Diffstat (limited to 'src/quick/accessible')
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp60
-rw-r--r--src/quick/accessible/qaccessiblequickitem_p.h2
-rw-r--r--src/quick/accessible/qaccessiblequickview.cpp57
-rw-r--r--src/quick/accessible/qqmlaccessible.cpp21
-rw-r--r--src/quick/accessible/qqmlaccessible_p.h2
5 files changed, 57 insertions, 85 deletions
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index c201076199..fe01326bbc 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -82,17 +82,42 @@ bool QAccessibleQuickItem::clipsChildren() const
return static_cast<QQuickItem *>(item())->clip();
}
+QAccessibleInterface *QAccessibleQuickItem::childAt(int x, int y) const
+{
+ if (item()->clip()) {
+ if (!rect().contains(x, y))
+ return 0;
+ }
+
+ const QList<QQuickItem*> kids = accessibleUnignoredChildren(item(), true);
+ for (int i = kids.count() - 1; i >= 0; --i) {
+ QAccessibleInterface *childIface = QAccessible::queryAccessibleInterface(kids.at(i));
+ if (QAccessibleInterface *childChild = childIface->childAt(x, y))
+ return childChild;
+ if (childIface && !childIface->state().invisible) {
+ if (childIface->rect().contains(x, y))
+ return childIface;
+ }
+ }
+
+ return 0;
+}
+
QAccessibleInterface *QAccessibleQuickItem::parent() const
{
QQuickItem *parent = item()->parentItem();
+ QQuickWindow *window = item()->window();
+ QQuickItem *ci = window ? window->contentItem() : 0;
+ while (parent && parent != ci)
+ parent = parent->parentItem();
+
if (parent) {
- QQuickWindow *window = item()->window();
- // Jump out to the scene widget if the parent is the root item.
- // There are two root items, QQuickWindow::rootItem and
- // QQuickView::declarativeRoot. The former is the true root item,
- // but is not a part of the accessibility tree. Check if we hit
- // it here and return an interface for the scene instead.
- if (window && (parent == window->contentItem())) {
+ if (parent == ci) {
+ // Jump out to the scene widget if the parent is the root item.
+ // There are two root items, QQuickWindow::rootItem and
+ // QQuickView::declarativeRoot. The former is the true root item,
+ // but is not a part of the accessibility tree. Check if we hit
+ // it here and return an interface for the scene instead.
return QAccessible::queryAccessibleInterface(window);
} else {
return QAccessible::queryAccessibleInterface(parent);
@@ -121,6 +146,19 @@ int QAccessibleQuickItem::indexOfChild(const QAccessibleInterface *iface) const
return kids.indexOf(static_cast<QQuickItem*>(iface->object()));
}
+QList<QQuickItem *> accessibleUnignoredChildren(QQuickItem *item, bool paintOrder)
+{
+ QList<QQuickItem *> items;
+ QList<QQuickItem*> childItems = paintOrder ? QQuickItemPrivate::get(item)->paintOrderChildItems()
+ : item->childItems();
+ Q_FOREACH (QQuickItem *child, childItems) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(child);
+ if (itemPrivate->isAccessible)
+ items.append(child);
+ }
+ return items;
+}
+
QList<QQuickItem *> QAccessibleQuickItem::childItems() const
{
if ( role() == QAccessible::Button ||
@@ -133,13 +171,7 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const
role() == QAccessible::ProgressBar)
return QList<QQuickItem *>();
- QList<QQuickItem *> items;
- Q_FOREACH (QQuickItem *child, item()->childItems()) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(child);
- if (itemPrivate->isAccessible)
- items.append(child);
- }
- return items;
+ return accessibleUnignoredChildren(item());
}
QAccessible::State QAccessibleQuickItem::state() const
diff --git a/src/quick/accessible/qaccessiblequickitem_p.h b/src/quick/accessible/qaccessiblequickitem_p.h
index 5cf120a802..84e82fff86 100644
--- a/src/quick/accessible/qaccessiblequickitem_p.h
+++ b/src/quick/accessible/qaccessiblequickitem_p.h
@@ -53,6 +53,7 @@ public:
QRect viewRect() const;
bool clipsChildren() const;
+ QAccessibleInterface *childAt(int x, int y) const;
QAccessibleInterface *parent() const;
QAccessibleInterface *child(int index) const;
@@ -118,6 +119,7 @@ private:
};
QRect itemScreenRect(QQuickItem *item);
+QList<QQuickItem *> accessibleUnignoredChildren(QQuickItem *item, bool paintOrder = false);
#endif // QT_NO_ACCESSIBILITY
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index cfd62b877d..db0b042d3b 100644
--- a/src/quick/accessible/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -53,7 +53,7 @@ QAccessibleQuickWindow::QAccessibleQuickWindow(QQuickWindow *object)
QQuickItem *QAccessibleQuickWindow::rootItem() const
{
if (QQuickItem *ci = window()->contentItem()) {
- const QList<QQuickItem *> &childItems = ci->childItems();
+ const QList<QQuickItem *> &childItems = accessibleUnignoredChildren(ci);
if (!childItems.isEmpty())
return childItems.first();
}
@@ -110,56 +110,17 @@ QString QAccessibleQuickWindow::text(QAccessible::Text text) const
return window()->title();
}
-
-/*!
- \internal
-
- Can also return \a item itself
- */
-static QQuickItem *childAt_helper(QQuickItem *item, int x, int y)
-{
- if (!item->isVisible() || !item->isEnabled())
- return 0;
-
- if (item->flags() & QQuickItem::ItemClipsChildrenToShape) {
- if (!itemScreenRect(item).contains(x, y))
- return 0;
- }
-
- QAccessibleInterface *accessibleInterface = QAccessible::queryAccessibleInterface(item);
- // this item has no Accessible attached property
- if (!accessibleInterface)
- return 0;
-
- if (accessibleInterface->childCount() == 0) {
- return (itemScreenRect(item).contains(x, y)) ? item : 0;
- }
-
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int i = children.count() - 1; i >= 0; --i) {
- QQuickItem *child = children.at(i);
- if (QQuickItem *childChild = childAt_helper(child, x, y))
- return childChild;
- }
-
- QRect screenRect = itemScreenRect(item);
-
- if (screenRect.contains(x, y))
- return item;
-
- return 0;
-}
-
QAccessibleInterface *QAccessibleQuickWindow::childAt(int x, int y) const
{
Q_ASSERT(window());
- QQuickItem *root = rootItem();
- if (root) {
- if (QQuickItem *item = childAt_helper(root, x, y))
- return QAccessible::queryAccessibleInterface(item);
- return QAccessible::queryAccessibleInterface(root);
+ for (int i = childCount() - 1; i >= 0; --i) {
+ QAccessibleInterface *childIface = child(i);
+ if (childIface && !childIface->state().invisible) {
+ if (QAccessibleInterface *iface = childIface->childAt(x, y))
+ return iface;
+ if (childIface->rect().contains(x, y))
+ return childIface;
+ }
}
return 0;
}
diff --git a/src/quick/accessible/qqmlaccessible.cpp b/src/quick/accessible/qqmlaccessible.cpp
index 65d321d0a1..53eb6a7a0d 100644
--- a/src/quick/accessible/qqmlaccessible.cpp
+++ b/src/quick/accessible/qqmlaccessible.cpp
@@ -54,27 +54,6 @@ QQmlAccessible::~QQmlAccessible()
{
}
-QAccessibleInterface *QQmlAccessible::childAt(int x, int y) const
-{
- // Note that this function will disregard stacking order.
- // (QAccessibleQuickView::childAt() does this correctly and more efficient)
-
- // If the item clips its children, we can return early if the coordinate is outside its rect
- if (clipsChildren()) {
- if (!rect().contains(x, y))
- return 0;
- }
-
- for (int i = childCount() - 1; i >= 0; --i) {
- QAccessibleInterface *childIface = child(i);
- if (childIface && !childIface->state().invisible) {
- if (childIface->rect().contains(x, y))
- return childIface;
- }
- }
- return 0;
-}
-
QAccessible::State QQmlAccessible::state() const
{
QAccessible::State state;
diff --git a/src/quick/accessible/qqmlaccessible_p.h b/src/quick/accessible/qqmlaccessible_p.h
index 38e3dcff59..5948f06cb5 100644
--- a/src/quick/accessible/qqmlaccessible_p.h
+++ b/src/quick/accessible/qqmlaccessible_p.h
@@ -64,7 +64,6 @@ public:
void *interface_cast(QAccessible::InterfaceType t);
virtual QRect viewRect() const = 0;
- QAccessibleInterface *childAt(int, int) const;
QAccessible::State state() const;
QStringList actionNames() const;
@@ -72,7 +71,6 @@ public:
QStringList keyBindingsForAction(const QString &actionName) const;
protected:
- virtual bool clipsChildren() const = 0;
// For subclasses, use instantiateObject factory method outside the class.
QQmlAccessible(QObject *object);
};