Fix for LayoutTests/accessibility/mac/search-text/search-text.html in IsolatedTree...
[WebKit-https.git] / Source / WebCore / accessibility / mac / AXObjectCacheMac.mm
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "AXObjectCache.h"
28
29 #if ENABLE(ACCESSIBILITY) && PLATFORM(MAC)
30
31 #import "AXIsolatedObject.h"
32 #import "AccessibilityObject.h"
33 #import "AccessibilityTable.h"
34 #import "RenderObject.h"
35 #import "WebAccessibilityObjectWrapperMac.h"
36 #import <pal/spi/cocoa/NSAccessibilitySPI.h>
37
38 #if USE(APPLE_INTERNAL_SDK)
39 #include <ApplicationServices/ApplicationServicesPriv.h>
40 #endif
41
42 #ifndef NSAccessibilityLiveRegionChangedNotification
43 #define NSAccessibilityLiveRegionChangedNotification @"AXLiveRegionChanged"
44 #endif
45
46 #ifndef NSAccessibilityLiveRegionCreatedNotification 
47 #define NSAccessibilityLiveRegionCreatedNotification @"AXLiveRegionCreated"
48 #endif
49
50 #ifndef NSAccessibilityTextStateChangeTypeKey
51 #define NSAccessibilityTextStateChangeTypeKey @"AXTextStateChangeType"
52 #endif
53
54 #ifndef NSAccessibilityTextStateSyncKey
55 #define NSAccessibilityTextStateSyncKey @"AXTextStateSync"
56 #endif
57
58 #ifndef NSAccessibilityTextSelectionDirection
59 #define NSAccessibilityTextSelectionDirection @"AXTextSelectionDirection"
60 #endif
61
62 #ifndef NSAccessibilityTextSelectionGranularity
63 #define NSAccessibilityTextSelectionGranularity @"AXTextSelectionGranularity"
64 #endif
65
66 #ifndef NSAccessibilityTextSelectionChangedFocus
67 #define NSAccessibilityTextSelectionChangedFocus @"AXTextSelectionChangedFocus"
68 #endif
69
70 #ifndef NSAccessibilityTextEditType
71 #define NSAccessibilityTextEditType @"AXTextEditType"
72 #endif
73
74 #ifndef NSAccessibilityTextChangeValues
75 #define NSAccessibilityTextChangeValues @"AXTextChangeValues"
76 #endif
77
78 #ifndef NSAccessibilityTextChangeValue
79 #define NSAccessibilityTextChangeValue @"AXTextChangeValue"
80 #endif
81
82 #ifndef NSAccessibilityTextChangeValueLength
83 #define NSAccessibilityTextChangeValueLength @"AXTextChangeValueLength"
84 #endif
85
86 #ifndef NSAccessibilityTextChangeValueStartMarker
87 #define NSAccessibilityTextChangeValueStartMarker @"AXTextChangeValueStartMarker"
88 #endif
89
90 #ifndef NSAccessibilityTextChangeElement
91 #define NSAccessibilityTextChangeElement @"AXTextChangeElement"
92 #endif
93
94 #ifndef NSAccessibilitySelectedTextMarkerRangeAttribute
95 #define NSAccessibilitySelectedTextMarkerRangeAttribute @"AXSelectedTextMarkerRange"
96 #endif
97
98 // Very large strings can negatively impact the performance of notifications, so this length is chosen to try to fit an average paragraph or line of text, but not allow strings to be large enough to hurt performance.
99 static const NSUInteger AXValueChangeTruncationLength = 1000;
100
101 // Check if platform provides enums for text change notifications
102 #ifndef AXTextStateChangeDefined
103 #define AXTextStateChangeDefined
104
105 typedef CF_ENUM(UInt32, AXTextStateChangeType)
106 {
107     kAXTextStateChangeTypeUnknown,
108     kAXTextStateChangeTypeEdit,
109     kAXTextStateChangeTypeSelectionMove,
110     kAXTextStateChangeTypeSelectionExtend,
111     kAXTextStateChangeTypeSelectionBoundary
112 };
113
114 typedef CF_ENUM(UInt32, AXTextEditType)
115 {
116     kAXTextEditTypeUnknown,
117     kAXTextEditTypeDelete,
118     kAXTextEditTypeInsert,
119     kAXTextEditTypeTyping,
120     kAXTextEditTypeDictation,
121     kAXTextEditTypeCut,
122     kAXTextEditTypePaste,
123     kAXTextEditTypeAttributesChange
124 };
125
126 typedef CF_ENUM(UInt32, AXTextSelectionDirection)
127 {
128     kAXTextSelectionDirectionUnknown = 0,
129     kAXTextSelectionDirectionBeginning,
130     kAXTextSelectionDirectionEnd,
131     kAXTextSelectionDirectionPrevious,
132     kAXTextSelectionDirectionNext,
133     kAXTextSelectionDirectionDiscontiguous
134 };
135
136 typedef CF_ENUM(UInt32, AXTextSelectionGranularity)
137 {
138     kAXTextSelectionGranularityUnknown,
139     kAXTextSelectionGranularityCharacter,
140     kAXTextSelectionGranularityWord,
141     kAXTextSelectionGranularityLine,
142     kAXTextSelectionGranularitySentence,
143     kAXTextSelectionGranularityParagraph,
144     kAXTextSelectionGranularityPage,
145     kAXTextSelectionGranularityDocument,
146     kAXTextSelectionGranularityAll
147 };
148
149 #endif // AXTextStateChangeDefined
150
151 static AXTextStateChangeType platformChangeTypeForWebCoreChangeType(WebCore::AXTextStateChangeType changeType)
152 {
153     switch (changeType) {
154     case WebCore::AXTextStateChangeTypeUnknown:
155         return kAXTextStateChangeTypeUnknown;
156     case WebCore::AXTextStateChangeTypeEdit:
157         return kAXTextStateChangeTypeEdit;
158     case WebCore::AXTextStateChangeTypeSelectionMove:
159         return kAXTextStateChangeTypeSelectionMove;
160     case WebCore::AXTextStateChangeTypeSelectionExtend:
161         return kAXTextStateChangeTypeSelectionExtend;
162     case WebCore::AXTextStateChangeTypeSelectionBoundary:
163         return kAXTextStateChangeTypeSelectionBoundary;
164     }
165 }
166
167 static AXTextEditType platformEditTypeForWebCoreEditType(WebCore::AXTextEditType changeType)
168 {
169     switch (changeType) {
170     case WebCore::AXTextEditTypeUnknown:
171         return kAXTextEditTypeUnknown;
172     case WebCore::AXTextEditTypeDelete:
173         return kAXTextEditTypeDelete;
174     case WebCore::AXTextEditTypeInsert:
175         return kAXTextEditTypeInsert;
176     case WebCore::AXTextEditTypeTyping:
177         return kAXTextEditTypeTyping;
178     case WebCore::AXTextEditTypeDictation:
179         return kAXTextEditTypeDictation;
180     case WebCore::AXTextEditTypeCut:
181         return kAXTextEditTypeCut;
182     case WebCore::AXTextEditTypePaste:
183         return kAXTextEditTypePaste;
184     case WebCore::AXTextEditTypeAttributesChange:
185         return kAXTextEditTypeAttributesChange;
186     }
187 }
188
189 static AXTextSelectionDirection platformDirectionForWebCoreDirection(WebCore::AXTextSelectionDirection direction)
190 {
191     switch (direction) {
192     case WebCore::AXTextSelectionDirectionUnknown:
193         return kAXTextSelectionDirectionUnknown;
194     case WebCore::AXTextSelectionDirectionBeginning:
195         return kAXTextSelectionDirectionBeginning;
196     case WebCore::AXTextSelectionDirectionEnd:
197         return kAXTextSelectionDirectionEnd;
198     case WebCore::AXTextSelectionDirectionPrevious:
199         return kAXTextSelectionDirectionPrevious;
200     case WebCore::AXTextSelectionDirectionNext:
201         return kAXTextSelectionDirectionNext;
202     case WebCore::AXTextSelectionDirectionDiscontiguous:
203         return kAXTextSelectionDirectionDiscontiguous;
204     }
205 }
206
207 static AXTextSelectionGranularity platformGranularityForWebCoreGranularity(WebCore::AXTextSelectionGranularity granularity)
208 {
209     switch (granularity) {
210     case WebCore::AXTextSelectionGranularityUnknown:
211         return kAXTextSelectionGranularityUnknown;
212     case WebCore::AXTextSelectionGranularityCharacter:
213         return kAXTextSelectionGranularityCharacter;
214     case WebCore::AXTextSelectionGranularityWord:
215         return kAXTextSelectionGranularityWord;
216     case WebCore::AXTextSelectionGranularityLine:
217         return kAXTextSelectionGranularityLine;
218     case WebCore::AXTextSelectionGranularitySentence:
219         return kAXTextSelectionGranularitySentence;
220     case WebCore::AXTextSelectionGranularityParagraph:
221         return kAXTextSelectionGranularityParagraph;
222     case WebCore::AXTextSelectionGranularityPage:
223         return kAXTextSelectionGranularityPage;
224     case WebCore::AXTextSelectionGranularityDocument:
225         return kAXTextSelectionGranularityDocument;
226     case WebCore::AXTextSelectionGranularityAll:
227         return kAXTextSelectionGranularityAll;
228     }
229 }
230
231 // The simple Cocoa calls in this file don't throw exceptions.
232
233 namespace WebCore {
234
235 void AXObjectCache::attachWrapper(AXCoreObject* obj)
236 {
237     RetainPtr<WebAccessibilityObjectWrapper> wrapper = adoptNS([[WebAccessibilityObjectWrapper alloc] initWithAccessibilityObject:obj]);
238     obj->setWrapper(wrapper.get());
239 }
240
241 static BOOL axShouldRepostNotificationsForTests = false;
242
243 void AXObjectCache::setShouldRepostNotificationsForTests(bool value)
244 {
245     axShouldRepostNotificationsForTests = value;
246 }
247
248 static void AXPostNotificationWithUserInfo(AccessibilityObjectWrapper *object, NSString *notification, id userInfo, bool skipSystemNotification = false)
249 {
250     if (id associatedPluginParent = [object associatedPluginParent])
251         object = associatedPluginParent;
252
253     // To simplify monitoring for notifications in tests, repost as a simple NSNotification instead of forcing test infrastucture to setup an IPC client and do all the translation between WebCore types and platform specific IPC types and back
254     if (UNLIKELY(axShouldRepostNotificationsForTests))
255         [object accessibilityPostedNotification:notification userInfo:userInfo];
256
257     if (skipSystemNotification)
258         return;
259
260     NSAccessibilityPostNotificationWithUserInfo(object, notification, userInfo);
261 }
262
263 void AXObjectCache::postPlatformNotification(AXCoreObject* obj, AXNotification notification)
264 {
265     if (!obj)
266         return;
267
268     bool skipSystemNotification = false;
269     // Some notifications are unique to Safari and do not have NSAccessibility equivalents.
270     NSString *macNotification;
271     switch (notification) {
272         case AXActiveDescendantChanged:
273             // An active descendant change for trees means a selected rows change.
274             if (obj->isTree() || obj->isTable())
275                 macNotification = NSAccessibilitySelectedRowsChangedNotification;
276             
277             // When a combobox uses active descendant, it means the selected item in its associated
278             // list has changed. In these cases we should use selected children changed, because
279             // we don't want the focus to change away from the combobox where the user is typing.
280             else if (obj->isComboBox() || obj->isList() || obj->isListBox())
281                 macNotification = NSAccessibilitySelectedChildrenChangedNotification;
282             else
283                 macNotification = NSAccessibilityFocusedUIElementChangedNotification;                
284             break;
285         case AXAutocorrectionOccured:
286             macNotification = @"AXAutocorrectionOccurred";
287             break;
288         case AXFocusedUIElementChanged:
289             macNotification = NSAccessibilityFocusedUIElementChangedNotification;
290             break;
291         case AXLayoutComplete:
292             macNotification = @"AXLayoutComplete";
293             break;
294         case AXLoadComplete:
295             macNotification = @"AXLoadComplete";
296             // Frame loading events are handled by the UIProcess on macOS to improve reliability.
297             // On macOS, before notifications are allowed by AppKit to be sent to clients, you need to have a client (e.g. VoiceOver)
298             // register for that notification. Because these new processes appear before VO has a chance to register, it will often
299             // miss AXLoadComplete notifications. By moving them to the UIProcess, we can eliminate that issue.
300             skipSystemNotification = true;
301             break;
302         case AXInvalidStatusChanged:
303             macNotification = @"AXInvalidStatusChanged";
304             break;
305         case AXSelectedChildrenChanged:
306             if (obj->isTable() && obj->isExposable())
307                 macNotification = NSAccessibilitySelectedRowsChangedNotification;
308             else
309                 macNotification = NSAccessibilitySelectedChildrenChangedNotification;
310             break;
311         case AXSelectedTextChanged:
312             macNotification = NSAccessibilitySelectedTextChangedNotification;
313             break;
314         case AXCheckedStateChanged:
315         case AXValueChanged:
316             macNotification = NSAccessibilityValueChangedNotification;
317             break;
318         case AXLiveRegionCreated:
319             macNotification = NSAccessibilityLiveRegionCreatedNotification;
320             break;
321         case AXLiveRegionChanged:
322             macNotification = NSAccessibilityLiveRegionChangedNotification;
323             break;
324         case AXRowCountChanged:
325             macNotification = NSAccessibilityRowCountChangedNotification;
326             break;
327         case AXRowExpanded:
328             macNotification = NSAccessibilityRowExpandedNotification;
329             break;
330         case AXRowCollapsed:
331             macNotification = NSAccessibilityRowCollapsedNotification;
332             break;
333         case AXElementBusyChanged:
334             macNotification = @"AXElementBusyChanged";
335             break;
336         case AXExpandedChanged:
337             macNotification = @"AXExpandedChanged";
338             break;
339         case AXMenuClosed:
340             macNotification = (id)kAXMenuClosedNotification;
341             break;
342         case AXMenuListItemSelected:
343             macNotification = (id)kAXMenuItemSelectedNotification;
344             break;
345         case AXPressDidSucceed:
346             macNotification = @"AXPressDidSucceed";
347             break;
348         case AXPressDidFail:
349             macNotification = @"AXPressDidFail";
350             break;
351         case AXMenuOpened:
352             macNotification = (id)kAXMenuOpenedNotification;
353             break;
354         default:
355             return;
356     }
357     
358     // NSAccessibilityPostNotification will call this method, (but not when running DRT), so ASSERT here to make sure it does not crash.
359     // https://bugs.webkit.org/show_bug.cgi?id=46662
360     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
361     ASSERT([obj->wrapper() accessibilityIsIgnored] || true);
362     ALLOW_DEPRECATED_DECLARATIONS_END
363
364     AXPostNotificationWithUserInfo(obj->wrapper(), macNotification, nil, skipSystemNotification);
365 }
366
367 void AXObjectCache::postTextStateChangePlatformNotification(AXCoreObject* object, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
368 {
369     if (!object)
370         object = rootWebArea();
371
372     if (!object)
373         return;
374
375     NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:5];
376     if (m_isSynchronizingSelection)
377         [userInfo setObject:@YES forKey:NSAccessibilityTextStateSyncKey];
378     if (intent.type != AXTextStateChangeTypeUnknown) {
379         [userInfo setObject:@(platformChangeTypeForWebCoreChangeType(intent.type)) forKey:NSAccessibilityTextStateChangeTypeKey];
380         switch (intent.type) {
381         case AXTextStateChangeTypeSelectionMove:
382         case AXTextStateChangeTypeSelectionExtend:
383         case AXTextStateChangeTypeSelectionBoundary:
384             [userInfo setObject:@(platformDirectionForWebCoreDirection(intent.selection.direction)) forKey:NSAccessibilityTextSelectionDirection];
385             switch (intent.selection.direction) {
386             case AXTextSelectionDirectionUnknown:
387                 break;
388             case AXTextSelectionDirectionBeginning:
389             case AXTextSelectionDirectionEnd:
390             case AXTextSelectionDirectionPrevious:
391             case AXTextSelectionDirectionNext:
392                 [userInfo setObject:@(platformGranularityForWebCoreGranularity(intent.selection.granularity)) forKey:NSAccessibilityTextSelectionGranularity];
393                 break;
394             case AXTextSelectionDirectionDiscontiguous:
395                 break;
396             }
397             if (intent.selection.focusChange)
398                 [userInfo setObject:@(intent.selection.focusChange) forKey:NSAccessibilityTextSelectionChangedFocus];
399             break;
400         case AXTextStateChangeTypeUnknown:
401         case AXTextStateChangeTypeEdit:
402             break;
403         }
404     }
405     if (!selection.isNone()) {
406         if (id textMarkerRange = [object->wrapper() textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()])
407             [userInfo setObject:textMarkerRange forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
408     }
409
410     if (id wrapper = object->wrapper())
411         [userInfo setObject:wrapper forKey:NSAccessibilityTextChangeElement];
412
413     if (auto root = rootWebArea()) {
414         AXPostNotificationWithUserInfo(rootWebArea()->wrapper(), NSAccessibilitySelectedTextChangedNotification, userInfo);
415         if (root->wrapper() != object->wrapper())
416             AXPostNotificationWithUserInfo(object->wrapper(), NSAccessibilitySelectedTextChangedNotification, userInfo);
417     }
418
419     [userInfo release];
420 }
421
422 static void addTextMarkerFor(NSMutableDictionary* change, AXCoreObject& object, const VisiblePosition& position)
423 {
424     if (position.isNull())
425         return;
426     if (id textMarker = [object.wrapper() textMarkerForVisiblePosition:position])
427         [change setObject:textMarker forKey:NSAccessibilityTextChangeValueStartMarker];
428 }
429
430 static void addTextMarkerFor(NSMutableDictionary* change, AXCoreObject& object, HTMLTextFormControlElement& textControl)
431 {
432     if (id textMarker = [object.wrapper() textMarkerForFirstPositionInTextControl:textControl])
433         [change setObject:textMarker forKey:NSAccessibilityTextChangeValueStartMarker];
434 }
435
436 template <typename TextMarkerTargetType>
437 static NSDictionary *textReplacementChangeDictionary(AXCoreObject& object, AXTextEditType type, const String& string, TextMarkerTargetType& markerTarget)
438 {
439     NSString *text = (NSString *)string;
440     NSUInteger length = [text length];
441     if (!length)
442         return nil;
443     NSMutableDictionary *change = [[NSMutableDictionary alloc] initWithCapacity:4];
444     [change setObject:@(platformEditTypeForWebCoreEditType(type)) forKey:NSAccessibilityTextEditType];
445     if (length > AXValueChangeTruncationLength) {
446         [change setObject:[NSNumber numberWithInt:length] forKey:NSAccessibilityTextChangeValueLength];
447         text = [text substringToIndex:AXValueChangeTruncationLength];
448     }
449     [change setObject:text forKey:NSAccessibilityTextChangeValue];
450     addTextMarkerFor(change, object, markerTarget);
451     return [change autorelease];
452 }
453
454 void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject* object, AXTextEditType type, const String& text, const VisiblePosition& position)
455 {
456     if (!text.length())
457         return;
458
459     postTextReplacementPlatformNotification(object, AXTextEditTypeUnknown, emptyString(), type, text, position);
460 }
461
462 static void postUserInfoForChanges(AXCoreObject& rootWebArea, AXCoreObject& object, NSMutableArray* changes)
463 {
464     NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:4];
465     [userInfo setObject:@(platformChangeTypeForWebCoreChangeType(AXTextStateChangeTypeEdit)) forKey:NSAccessibilityTextStateChangeTypeKey];
466     if (changes.count)
467         [userInfo setObject:changes forKey:NSAccessibilityTextChangeValues];
468
469     if (id wrapper = object.wrapper())
470         [userInfo setObject:wrapper forKey:NSAccessibilityTextChangeElement];
471
472     AXPostNotificationWithUserInfo(rootWebArea.wrapper(), NSAccessibilityValueChangedNotification, userInfo);
473     if (rootWebArea.wrapper() != object.wrapper())
474         AXPostNotificationWithUserInfo(object.wrapper(), NSAccessibilityValueChangedNotification, userInfo);
475
476     [userInfo release];
477 }
478
479 void AXObjectCache::postTextReplacementPlatformNotification(AXCoreObject* object, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition& position)
480 {
481     if (!object)
482         object = rootWebArea();
483
484     if (!object)
485         return;
486
487     NSMutableArray *changes = [[NSMutableArray alloc] initWithCapacity:2];
488     if (NSDictionary *change = textReplacementChangeDictionary(*object, deletionType, deletedText, position))
489         [changes addObject:change];
490     if (NSDictionary *change = textReplacementChangeDictionary(*object, insertionType, insertedText, position))
491         [changes addObject:change];
492     postUserInfoForChanges(*rootWebArea(), *object, changes);
493     [changes release];
494 }
495
496 void AXObjectCache::postTextReplacementPlatformNotificationForTextControl(AXCoreObject* object, const String& deletedText, const String& insertedText, HTMLTextFormControlElement& textControl)
497 {
498     if (!object)
499         object = rootWebArea();
500
501     if (!object)
502         return;
503
504     NSMutableArray *changes = [[NSMutableArray alloc] initWithCapacity:2];
505     if (NSDictionary *change = textReplacementChangeDictionary(*object, AXTextEditTypeDelete, deletedText, textControl))
506         [changes addObject:change];
507     if (NSDictionary *change = textReplacementChangeDictionary(*object, AXTextEditTypeInsert, insertedText, textControl))
508         [changes addObject:change];
509     postUserInfoForChanges(*rootWebArea(), *object, changes);
510     [changes release];
511 }
512
513 void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject* axFrameObject, AXLoadingEvent loadingEvent)
514 {
515     if (!axFrameObject)
516         return;
517     
518     if (loadingEvent == AXLoadingFinished && axFrameObject->document() == axFrameObject->topDocument())
519         postPlatformNotification(axFrameObject, AXLoadComplete);
520 }
521
522 void AXObjectCache::platformHandleFocusedUIElementChanged(Node*, Node*)
523 {
524     NSAccessibilityHandleFocusChanged();
525     // AXFocusChanged is a test specific notification name and not something a real AT will be listening for
526     if (UNLIKELY(!axShouldRepostNotificationsForTests))
527         return;
528
529     auto* rootWebArea = this->rootWebArea();
530     if (!rootWebArea)
531         return;
532
533     [rootWebArea->wrapper() accessibilityPostedNotification:@"AXFocusChanged" userInfo:nil];
534 }
535
536 void AXObjectCache::handleScrolledToAnchor(const Node*)
537 {
538 }
539
540 void AXObjectCache::platformPerformDeferredCacheUpdate()
541 {
542 }
543
544 }
545
546 #endif // ENABLE(ACCESSIBILITY) && PLATFORM(MAC)