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 plugins 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#include "qcocoaaccessibilityelement.h" 40#include "qcocoaaccessibility.h" 41#include "qcocoahelpers.h" 42#include "qcocoawindow.h" 43#include "qcocoascreen.h" 44 45#include <QtGui/private/qaccessiblecache_p.h> 46#include <QtAccessibilitySupport/private/qaccessiblebridgeutils_p.h> 47#include <QtGui/qaccessible.h> 48 49#import <AppKit/NSAccessibility.h> 50 51QT_USE_NAMESPACE 52 53#ifndef QT_NO_ACCESSIBILITY 54 55/** 56 * Converts between absolute character offsets and line numbers of a 57 * QAccessibleTextInterface. Works in exactly one of two modes: 58 * 59 * - Pass *line == -1 in order to get a line containing character at the given 60 * *offset 61 * - Pass *offset == -1 in order to get the offset of first character of the 62 * given *line 63 * 64 * You can optionally also pass non-NULL `start` and `end`, which will in both 65 * modes be filled with the offset of the first and last characters of the 66 * relevant line. 67 */ 68static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *offset, NSUInteger *start = 0, NSUInteger *end = 0) 69{ 70 Q_ASSERT(*line == -1 || *offset == -1); 71 Q_ASSERT(*line != -1 || *offset != -1); 72 Q_ASSERT(*offset <= text->characterCount()); 73 74 int curLine = -1; 75 int curStart = 0, curEnd = 0; 76 77 do { 78 curStart = curEnd; 79 text->textAtOffset(curStart, QAccessible::LineBoundary, &curStart, &curEnd); 80 // If the text is empty then we just return 81 if (curStart == -1 || curEnd == -1) { 82 if (start) 83 *start = 0; 84 if (end) 85 *end = 0; 86 return; 87 } 88 ++curLine; 89 { 90 // check for a case where a single word longer than the text edit's width and gets wrapped 91 // in the middle of the word; in this case curEnd will be an offset belonging to the next line 92 // and therefore nextEnd will not be equal to curEnd 93 int nextStart; 94 int nextEnd; 95 text->textAtOffset(curEnd, QAccessible::LineBoundary, &nextStart, &nextEnd); 96 if (nextEnd == curEnd) 97 ++curEnd; 98 } 99 } while ((*line == -1 || curLine < *line) && (*offset == -1 || (curEnd <= *offset)) && curEnd <= text->characterCount()); 100 101 curEnd = qMin(curEnd, text->characterCount()); 102 103 if (*line == -1) 104 *line = curLine; 105 if (*offset == -1) 106 *offset = curStart; 107 108 Q_ASSERT(curStart >= 0); 109 Q_ASSERT(curEnd >= 0); 110 if (start) 111 *start = curStart; 112 if (end) 113 *end = curEnd; 114} 115 116@implementation QMacAccessibilityElement { 117 QAccessible::Id axid; 118} 119 120- (instancetype)initWithId:(QAccessible::Id)anId 121{ 122 Q_ASSERT((int)anId < 0); 123 self = [super init]; 124 if (self) { 125 axid = anId; 126 } 127 128 return self; 129} 130 131+ (instancetype)elementWithId:(QAccessible::Id)anId 132{ 133 Q_ASSERT(anId); 134 if (!anId) 135 return nil; 136 137 QAccessibleCache *cache = QAccessibleCache::instance(); 138 139 QMacAccessibilityElement *element = cache->elementForId(anId); 140 if (!element) { 141 QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); 142 Q_ASSERT(iface); 143 if (!iface || !iface->isValid()) 144 return nil; 145 element = [[self alloc] initWithId:anId]; 146 cache->insertElement(anId, element); 147 } 148 return element; 149} 150 151- (void)invalidate { 152 axid = 0; 153 NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification); 154 [self release]; 155} 156 157- (void)dealloc { 158 [super dealloc]; 159} 160 161- (BOOL)isEqual:(id)object { 162 if ([object isKindOfClass:[QMacAccessibilityElement class]]) { 163 QMacAccessibilityElement *other = object; 164 return other->axid == axid; 165 } else { 166 return NO; 167 } 168} 169 170- (NSUInteger)hash { 171 return axid; 172} 173 174// 175// accessibility protocol 176// 177 178- (BOOL)isAccessibilityFocused 179{ 180 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 181 if (!iface || !iface->isValid()) { 182 return false; 183 } 184 // Just check if the app thinks we're focused. 185 id focusedElement = NSApp.accessibilityApplicationFocusedUIElement; 186 return [focusedElement isEqual:self]; 187} 188 189// attributes 190 191+ (id) lineNumberForIndex: (int)index forText:(const QString &)text 192{ 193 QStringRef textBefore = QStringRef(&text, 0, index); 194 int newlines = textBefore.count(QLatin1Char('\n')); 195 return @(newlines); 196} 197 198- (BOOL) accessibilityNotifiesWhenDestroyed { 199 return YES; 200} 201 202- (NSString *) accessibilityRole { 203 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 204 if (!iface || !iface->isValid()) 205 return NSAccessibilityUnknownRole; 206 return QCocoaAccessible::macRole(iface); 207} 208 209- (NSString *) accessibilitySubRole { 210 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 211 if (!iface || !iface->isValid()) 212 return NSAccessibilityUnknownRole; 213 return QCocoaAccessible::macSubrole(iface); 214} 215 216- (NSString *) accessibilityRoleDescription { 217 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 218 if (!iface || !iface->isValid()) 219 return NSAccessibilityUnknownRole; 220 return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole); 221} 222 223- (NSArray *) accessibilityChildren { 224 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 225 if (!iface || !iface->isValid()) 226 return nil; 227 return QCocoaAccessible::unignoredChildren(iface); 228} 229 230- (id) accessibilityWindow { 231 // We're in the same window as our parent. 232 return [self.accessibilityParent accessibilityWindow]; 233} 234 235- (id) accessibilityTopLevelUIElementAttribute { 236 // We're in the same top level element as our parent. 237 return [self.accessibilityParent accessibilityTopLevelUIElementAttribute]; 238} 239 240- (NSString *) accessibilityTitle { 241 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 242 if (!iface || !iface->isValid()) 243 return nil; 244 if (iface->role() == QAccessible::StaticText) 245 return nil; 246 return iface->text(QAccessible::Name).toNSString(); 247} 248 249- (BOOL) accessibilityEnabledAttribute { 250 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 251 if (!iface || !iface->isValid()) 252 return false; 253 return !iface->state().disabled; 254} 255 256- (id)accessibilityParent { 257 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 258 if (!iface || !iface->isValid()) 259 return nil; 260 261 // macOS expects that the hierarchy is: 262 // App -> Window -> Children 263 // We don't actually have the window reflected properly in QAccessibility. 264 // Check if the parent is the application and then instead return the native window. 265 266 if (QAccessibleInterface *parent = iface->parent()) { 267 if (parent->role() != QAccessible::Application) { 268 QAccessible::Id parentId = QAccessible::uniqueId(parent); 269 return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId: parentId]); 270 } 271 } 272 273 if (QWindow *window = iface->window()) { 274 QPlatformWindow *platformWindow = window->handle(); 275 if (platformWindow) { 276 QCocoaWindow *win = static_cast<QCocoaWindow*>(platformWindow); 277 return NSAccessibilityUnignoredAncestor(qnsview_cast(win->view())); 278 } 279 } 280 return nil; 281} 282 283- (NSRect)accessibilityFrame { 284 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 285 if (!iface || !iface->isValid()) 286 return NSZeroRect; 287 return QCocoaScreen::mapToNative(iface->rect()); 288} 289 290- (NSString*)accessibilityLabel { 291 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 292 if (!iface || !iface->isValid()) { 293 qWarning() << "Called accessibilityLabel on invalid object: " << axid; 294 return nil; 295 } 296 return iface->text(QAccessible::Description).toNSString(); 297} 298 299- (void)setAccessibilityLabel:(NSString*)label{ 300 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 301 if (!iface || !iface->isValid()) 302 return; 303 iface->setText(QAccessible::Description, QString::fromNSString(label)); 304} 305 306- (id) accessibilityMinValue:(QAccessibleInterface*)iface { 307 if (QAccessibleValueInterface *val = iface->valueInterface()) 308 return @(val->minimumValue().toDouble()); 309 return nil; 310} 311 312- (id) accessibilityMaxValue:(QAccessibleInterface*)iface { 313 if (QAccessibleValueInterface *val = iface->valueInterface()) 314 return @(val->maximumValue().toDouble()); 315 return nil; 316} 317 318- (id) accessibilityValue { 319 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 320 if (!iface || !iface->isValid()) 321 return nil; 322 323 // VoiceOver asks for the value attribute for all elements. Return nil 324 // if we don't want the element to have a value attribute. 325 if (!QCocoaAccessible::hasValueAttribute(iface)) 326 return nil; 327 328 return QCocoaAccessible::getValueAttribute(iface); 329} 330 331- (NSInteger) accessibilityNumberOfCharacters { 332 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 333 if (!iface || !iface->isValid()) 334 return 0; 335 if (QAccessibleTextInterface *text = iface->textInterface()) 336 return text->characterCount(); 337 return 0; 338} 339 340- (NSString *) accessibilitySelectedText { 341 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 342 if (!iface || !iface->isValid()) 343 return nil; 344 if (QAccessibleTextInterface *text = iface->textInterface()) { 345 int start = 0; 346 int end = 0; 347 text->selection(0, &start, &end); 348 return text->text(start, end).toNSString(); 349 } 350 return nil; 351} 352 353- (NSRange) accessibilitySelectedTextRange { 354 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 355 if (!iface || !iface->isValid()) 356 return NSRange(); 357 if (QAccessibleTextInterface *text = iface->textInterface()) { 358 int start = 0; 359 int end = 0; 360 if (text->selectionCount() > 0) { 361 text->selection(0, &start, &end); 362 } else { 363 start = text->cursorPosition(); 364 end = start; 365 } 366 return NSMakeRange(quint32(start), quint32(end - start)); 367 } 368 return NSMakeRange(0, 0); 369} 370 371- (NSInteger)accessibilityLineForIndex:(NSInteger)index { 372 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 373 if (!iface || !iface->isValid()) 374 return 0; 375 if (QAccessibleTextInterface *text = iface->textInterface()) { 376 QString textToPos = text->text(0, index); 377 return textToPos.count('\n'); 378 } 379 return 0; 380} 381 382- (NSRange)accessibilityVisibleCharacterRange { 383 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 384 if (!iface || !iface->isValid()) 385 return NSRange(); 386 // FIXME This is not correct and may impact performance for big texts 387 if (QAccessibleTextInterface *text = iface->textInterface()) 388 return NSMakeRange(0, static_cast<uint>(text->characterCount())); 389 return NSMakeRange(0, static_cast<uint>(iface->text(QAccessible::Name).length())); 390} 391 392- (NSInteger) accessibilityInsertionPointLineNumber { 393 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 394 if (!iface || !iface->isValid()) 395 return 0; 396 if (QAccessibleTextInterface *text = iface->textInterface()) { 397 int position = text->cursorPosition(); 398 return [self accessibilityLineForIndex:position]; 399 } 400 return 0; 401} 402 403- (NSArray *)accessibilityParameterizedAttributeNames { 404 405 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 406 if (!iface || !iface->isValid()) { 407 qWarning() << "Called attribute on invalid object: " << axid; 408 return nil; 409 } 410 411 if (iface->textInterface()) { 412 return @[ 413 NSAccessibilityStringForRangeParameterizedAttribute, 414 NSAccessibilityLineForIndexParameterizedAttribute, 415 NSAccessibilityRangeForLineParameterizedAttribute, 416 NSAccessibilityRangeForPositionParameterizedAttribute, 417// NSAccessibilityRangeForIndexParameterizedAttribute, 418 NSAccessibilityBoundsForRangeParameterizedAttribute, 419// NSAccessibilityRTFForRangeParameterizedAttribute, 420 NSAccessibilityStyleRangeForIndexParameterizedAttribute, 421 NSAccessibilityAttributedStringForRangeParameterizedAttribute 422 ]; 423 } 424 425 return nil; 426} 427 428- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter { 429 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 430 if (!iface || !iface->isValid()) { 431 qWarning() << "Called attribute on invalid object: " << axid; 432 return nil; 433 } 434 435 if (!iface->textInterface()) 436 return nil; 437 438 if ([attribute isEqualToString: NSAccessibilityStringForRangeParameterizedAttribute]) { 439 NSRange range = [parameter rangeValue]; 440 QString text = iface->textInterface()->text(range.location, range.location + range.length); 441 return text.toNSString(); 442 } 443 if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) { 444 int index = [parameter intValue]; 445 if (index < 0 || index > iface->textInterface()->characterCount()) 446 return nil; 447 int line = 0; // true for all single line edits 448 if (iface->state().multiLine) { 449 line = -1; 450 convertLineOffset(iface->textInterface(), &line, &index); 451 } 452 return @(line); 453 } 454 if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { 455 int line = [parameter intValue]; 456 if (line < 0) 457 return nil; 458 int lineOffset = -1; 459 NSUInteger startOffset = 0; 460 NSUInteger endOffset = 0; 461 convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset); 462 return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)]; 463 } 464 if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) { 465 NSRange range = [parameter rangeValue]; 466 QRect firstRect = iface->textInterface()->characterRect(range.location); 467 QRectF rect; 468 if (range.length > 0) { 469 NSUInteger position = range.location + range.length - 1; 470 if (position > range.location && iface->textInterface()->text(position, position + 1) == QStringLiteral("\n")) 471 --position; 472 QRect lastRect = iface->textInterface()->characterRect(position); 473 rect = firstRect.united(lastRect); 474 } else { 475 rect = firstRect; 476 rect.setWidth(1); 477 } 478 return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)]; 479 } 480 if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) { 481 NSRange range = [parameter rangeValue]; 482 QString text = iface->textInterface()->text(range.location, range.location + range.length); 483 return [[NSAttributedString alloc] initWithString:text.toNSString()]; 484 } else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) { 485 QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint(); 486 int offset = iface->textInterface()->offsetAtPoint(point); 487 return [NSValue valueWithRange:NSMakeRange(static_cast<NSUInteger>(offset), 1)]; 488 } else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) { 489 int start = 0; 490 int end = 0; 491 iface->textInterface()->attributes([parameter intValue], &start, &end); 492 return [NSValue valueWithRange:NSMakeRange(static_cast<NSUInteger>(start), static_cast<NSUInteger>(end - start))]; 493 } 494 return nil; 495} 496 497- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { 498 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 499 if (!iface || !iface->isValid()) 500 return NO; 501 502 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { 503 return iface->state().focusable ? YES : NO; 504 } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { 505 if (iface->textInterface() && iface->state().editable) 506 return YES; 507 if (iface->valueInterface()) 508 return YES; 509 return NO; 510 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { 511 return iface->textInterface() ? YES : NO; 512 } 513 return NO; 514} 515 516- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { 517 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 518 if (!iface || !iface->isValid()) 519 return; 520 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { 521 if (QAccessibleActionInterface *action = iface->actionInterface()) 522 action->doAction(QAccessibleActionInterface::setFocusAction()); 523 } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { 524 if (iface->textInterface()) { 525 QString text = QString::fromNSString((NSString *)value); 526 iface->setText(QAccessible::Value, text); 527 } else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) { 528 double val = [value doubleValue]; 529 valueIface->setCurrentValue(val); 530 } 531 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { 532 if (QAccessibleTextInterface *text = iface->textInterface()) { 533 NSRange range = [value rangeValue]; 534 if (range.length > 0) 535 text->setSelection(0, range.location, range.location + range.length); 536 else 537 text->setCursorPosition(range.location); 538 } 539 } 540} 541 542// actions 543 544- (NSArray *)accessibilityActionNames { 545 NSMutableArray *nsActions = [[NSMutableArray new] autorelease]; 546 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 547 if (!iface || !iface->isValid()) 548 return nsActions; 549 550 const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface); 551 for (const QString &qtAction : supportedActionNames) { 552 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction); 553 if (nsAction) 554 [nsActions addObject : nsAction]; 555 } 556 557 return nsActions; 558} 559 560- (NSString *)accessibilityActionDescription:(NSString *)action { 561 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 562 if (!iface || !iface->isValid()) 563 return nil; // FIXME is that the right return type?? 564 QString qtAction = QCocoaAccessible::translateAction(action, iface); 565 QString description; 566 // Return a description from the action interface if this action is not known to the OS. 567 if (qtAction.isEmpty()) { 568 if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) { 569 qtAction = QString::fromNSString((NSString *)action); 570 description = actionInterface->localizedActionDescription(qtAction); 571 } 572 } else { 573 description = qAccessibleLocalizedActionDescription(qtAction); 574 } 575 return description.toNSString(); 576} 577 578- (void)accessibilityPerformAction:(NSString *)action { 579 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 580 if (iface && iface->isValid()) { 581 const QString qtAction = QCocoaAccessible::translateAction(action, iface); 582 QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction); 583 } 584} 585 586// misc 587 588- (BOOL)accessibilityIsIgnored { 589 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 590 if (!iface || !iface->isValid()) 591 return true; 592 return QCocoaAccessible::shouldBeIgnored(iface); 593} 594 595- (id)accessibilityHitTest:(NSPoint)point { 596 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 597 if (!iface || !iface->isValid()) { 598// qDebug("Hit test: INVALID"); 599 return NSAccessibilityUnignoredAncestor(self); 600 } 601 602 QPointF screenPoint = QCocoaScreen::mapFromNative(point); 603 QAccessibleInterface *childInterface = iface->childAt(screenPoint.x(), screenPoint.y()); 604 // No child found, meaning we hit this element. 605 if (!childInterface || !childInterface->isValid()) 606 return NSAccessibilityUnignoredAncestor(self); 607 608 // find the deepest child at the point 609 QAccessibleInterface *childOfChildInterface = nullptr; 610 do { 611 childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y()); 612 if (childOfChildInterface && childOfChildInterface->isValid()) 613 childInterface = childOfChildInterface; 614 } while (childOfChildInterface && childOfChildInterface->isValid()); 615 616 QAccessible::Id childId = QAccessible::uniqueId(childInterface); 617 // hit a child, forward to child accessible interface. 618 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childId]; 619 if (accessibleElement) 620 return NSAccessibilityUnignoredAncestor(accessibleElement); 621 return NSAccessibilityUnignoredAncestor(self); 622} 623 624- (id)accessibilityFocusedUIElement { 625 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); 626 627 if (!iface || !iface->isValid()) { 628 qWarning("FocusedUIElement for INVALID"); 629 return nil; 630 } 631 632 QAccessibleInterface *childInterface = iface->focusChild(); 633 if (childInterface && childInterface->isValid()) { 634 QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); 635 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childAxid]; 636 return NSAccessibilityUnignoredAncestor(accessibleElement); 637 } 638 639 return NSAccessibilityUnignoredAncestor(self); 640} 641 642@end 643 644#endif // QT_NO_ACCESSIBILITY 645