Coverage Report

Created: 2025-07-23 08:13

/src/qtbase/src/gui/accessible/qaccessiblecache.cpp
Line
Count
Source (jump to first uncovered line)
1
/****************************************************************************
2
**
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
5
**
6
** This file is part of the QtGui module of the Qt Toolkit.
7
**
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
16
**
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 3 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 3 requirements
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24
**
25
** GNU General Public License Usage
26
** Alternatively, this file may be used under the terms of the GNU
27
** General Public License version 2.0 or (at your option) the GNU General
28
** Public license version 3 or any later version approved by the KDE Free
29
** Qt Foundation. The licenses are as published by the Free Software
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31
** included in the packaging of this file. Please review the following
32
** information to ensure the GNU General Public License requirements will
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34
** https://www.gnu.org/licenses/gpl-3.0.html.
35
**
36
** $QT_END_LICENSE$
37
**
38
****************************************************************************/
39
40
#include "qaccessiblecache_p.h"
41
#include <QtCore/qdebug.h>
42
#include <QtCore/qloggingcategory.h>
43
44
#ifndef QT_NO_ACCESSIBILITY
45
46
QT_BEGIN_NAMESPACE
47
48
Q_LOGGING_CATEGORY(lcAccessibilityCache, "qt.accessibility.cache");
49
50
/*!
51
    \class QAccessibleCache
52
    \internal
53
    \brief Maintains a cache of accessible interfaces.
54
*/
55
56
static QAccessibleCache *accessibleCache = nullptr;
57
58
static void cleanupAccessibleCache()
59
0
{
60
0
    delete accessibleCache;
61
0
    accessibleCache = nullptr;
62
0
}
63
64
QAccessibleCache::~QAccessibleCache()
65
0
{
66
0
    for (QAccessible::Id id: idToInterface.keys())
67
0
        deleteInterface(id);
68
0
}
69
70
QAccessibleCache *QAccessibleCache::instance()
71
0
{
72
0
    if (!accessibleCache) {
73
0
        accessibleCache = new QAccessibleCache;
74
0
        qAddPostRoutine(cleanupAccessibleCache);
75
0
    }
76
0
    return accessibleCache;
77
0
}
78
79
/*
80
  The ID is always in the range [INT_MAX+1, UINT_MAX].
81
  This makes it easy on windows to reserve the positive integer range
82
  for the index of a child and not clash with the unique ids.
83
*/
84
QAccessible::Id QAccessibleCache::acquireId() const
85
0
{
86
0
    static const QAccessible::Id FirstId = QAccessible::Id(INT_MAX) + 1;
87
0
    static QAccessible::Id lastUsedId = FirstId;
88
89
0
    while (idToInterface.contains(lastUsedId)) {
90
        // (wrap back when when we reach UINT_MAX - 1)
91
        // -1 because on Android -1 is taken for the "View" so just avoid it completely for consistency
92
0
        if (lastUsedId == UINT_MAX - 1)
93
0
            lastUsedId = FirstId;
94
0
        else
95
0
            ++lastUsedId;
96
0
    }
97
98
0
    return lastUsedId;
99
0
}
100
101
QAccessibleInterface *QAccessibleCache::interfaceForId(QAccessible::Id id) const
102
0
{
103
0
    return idToInterface.value(id);
104
0
}
105
106
QAccessible::Id QAccessibleCache::idForInterface(QAccessibleInterface *iface) const
107
0
{
108
0
    return interfaceToId.value(iface);
109
0
}
110
111
QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *iface) const
112
0
{
113
0
    Q_ASSERT(iface);
114
0
    Q_UNUSED(object)
115
116
    // object might be 0
117
0
    Q_ASSERT(!objectToId.contains(object));
118
0
    Q_ASSERT_X(!interfaceToId.contains(iface), "", "Accessible interface inserted into cache twice!");
119
120
0
    QAccessible::Id id = acquireId();
121
0
    QObject *obj = iface->object();
122
0
    Q_ASSERT(object == obj);
123
0
    if (obj) {
124
0
        objectToId.insert(obj, id);
125
0
        connect(obj, &QObject::destroyed, this, &QAccessibleCache::objectDestroyed);
126
0
    }
127
0
    idToInterface.insert(id, iface);
128
0
    interfaceToId.insert(iface, id);
129
0
    qCDebug(lcAccessibilityCache) << "insert - id:" << id << " iface:" << iface;
130
0
    return id;
131
0
}
132
133
void QAccessibleCache::objectDestroyed(QObject* obj)
134
0
{
135
0
    QAccessible::Id id = objectToId.value(obj);
136
0
    if (id) {
137
0
        Q_ASSERT_X(idToInterface.contains(id), "", "QObject with accessible interface deleted, where interface not in cache!");
138
0
        deleteInterface(id, obj);
139
0
    }
140
0
}
141
142
void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj)
143
0
{
144
0
    QAccessibleInterface *iface = idToInterface.take(id);
145
0
    qCDebug(lcAccessibilityCache) << "delete - id:" << id << " iface:" << iface;
146
0
    if (!iface) // the interface may be deleted already
147
0
        return;
148
0
    interfaceToId.take(iface);
149
0
    if (!obj)
150
0
        obj = iface->object();
151
0
    if (obj)
152
0
        objectToId.remove(obj);
153
0
    delete iface;
154
155
#ifdef Q_OS_MAC
156
    removeCocoaElement(id);
157
#endif
158
0
}
159
160
QT_END_NAMESPACE
161
162
#include "moc_qaccessiblecache_p.cpp"
163
164
#endif