REGRESSION (257739) [ Mac wk2 Release ] multiple tests crashing in WebCore::postUserI...
[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 #import <pal/spi/mac/HIServicesSPI.h>
38
39 #if USE(APPLE_INTERNAL_SDK)
40 #include <ApplicationServices/ApplicationServicesPriv.h>
41 #endif
42
43 #ifndef NSAccessibilityLiveRegionChangedNotification
44 #define NSAccessibilityLiveRegionChangedNotification @"AXLiveRegionChanged"
45 #endif
46
47 #ifndef NSAccessibilityLiveRegionCreatedNotification 
48 #define NSAccessibilityLiveRegionCreatedNotification @"AXLiveRegionCreated"
49 #endif
50
51 #ifndef NSAccessibilityTextStateChangeTypeKey
52 #define NSAccessibilityTextStateChangeTypeKey @"AXTextStateChangeType"
53 #endif
54
55 #ifndef NSAccessibilityTextStateSyncKey
56 #define NSAccessibilityTextStateSyncKey @"AXTextStateSync"
57 #endif
58
59 #ifndef NSAccessibilityTextSelectionDirection
60 #define NSAccessibilityTextSelectionDirection @"AXTextSelectionDirection"
61 #endif
62
63 #ifndef NSAccessibilityTextSelectionGranularity
64 #define NSAccessibilityTextSelectionGranularity @"AXTextSelectionGranularity"
65 #endif
66
67 #ifndef NSAccessibilityTextSelectionChangedFocus
68 #define NSAccessibilityTextSelectionChangedFocus @"AXTextSelectionChangedFocus"
69 #endif
70
71 #ifndef NSAccessibilityTextEditType
72 #define NSAccessibilityTextEditType @"AXTextEditType"
73 #endif
74
75 #ifndef NSAccessibilityTextChangeValues
76 #define NSAccessibilityTextChangeValues @"AXTextChangeValues"
77 #endif
78
79 #ifndef NSAccessibilityTextChangeValue
80 #define NSAccessibilityTextChangeValue @"AXTextChangeValue"
81 #endif
82
83 #ifndef NSAccessibilityTextChangeValueLength
84 #define NSAccessibilityTextChangeValueLength @"AXTextChangeValueLength"
85 #endif
86
87 #ifndef NSAccessibilityTextChangeValueStartMarker
88 #define NSAccessibilityTextChangeValueStartMarker @"AXTextChangeValueStartMarker"
89 #endif
90
91 #ifndef NSAccessibilityTextChangeElement
92 #define NSAccessibilityTextChangeElement @"AXTextChangeElement"
93 #endif
94
95 #ifndef NSAccessibilitySelectedTextMarkerRangeAttribute
96 #define NSAccessibilitySelectedTextMarkerRangeAttribute @"AXSelectedTextMarkerRange"
97 #endif
98
99 // 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.
100 static const NSUInteger AXValueChangeTruncationLength = 1000;
101
102 // Check if platform provides enums for text change notifications
103 #ifndef AXTextStateChangeDefined
104 #define AXTextStateChangeDefined
105
106 typedef CF_ENUM(UInt32, AXTextStateChangeType)
107 {
108     kAXTextStateChangeTypeUnknown,
109     kAXTextStateChangeTypeEdit,
110     kAXTextStateChangeTypeSelectionMove,
111     kAXTextStateChangeTypeSelectionExtend,
112     kAXTextStateChangeTypeSelectionBoundary
113 };
114
115 typedef CF_ENUM(UInt32, AXTextEditType)
116 {
117     kAXTextEditTypeUnknown,
118     kAXTextEditTypeDelete,
119     kAXTextEditTypeInsert,
120     kAXTextEditTypeTyping,
121     kAXTextEditTypeDictation,
122     kAXTextEditTypeCut,
123     kAXTextEditTypePaste,
124     kAXTextEditTypeAttributesChange
125 };
126
127 typedef CF_ENUM(UInt32, AXTextSelectionDirection)
128 {
129     kAXTextSelectionDirectionUnknown = 0,
130     kAXTextSelectionDirectionBeginning,
131     kAXTextSelectionDirectionEnd,
132     kAXTextSelectionDirectionPrevious,
133     kAXTextSelectionDirectionNext,
134     kAXTextSelectionDirectionDiscontiguous
135 };
136
137 typedef CF_ENUM(UInt32, AXTextSelectionGranularity)
138 {
139     kAXTextSelectionGranularityUnknown,
140     kAXTextSelectionGranularityCharacter,
141     kAXTextSelectionGranularityWord,
142     kAXTextSelectionGranularityLine,
143     kAXTextSelectionGranularitySentence,
144     kAXTextSelectionGranularityParagraph,
145     kAXTextSelectionGranularityPage,
146     kAXTextSelectionGranularityDocument,
147     kAXTextSelectionGranularityAll
148 };
149
150 #endif // AXTextStateChangeDefined
151
152 static AXTextStateChangeType platformChangeTypeForWebCoreChangeType(WebCore::AXTextStateChangeType changeType)
153 {
154     switch (changeType) {
155     case WebCore::AXTextStateChangeTypeUnknown:
156         return kAXTextStateChangeTypeUnknown;
157     case WebCore::AXTextStateChangeTypeEdit:
158         return kAXTextStateChangeTypeEdit;
159     case WebCore::AXTextStateChangeTypeSelectionMove:
160         return kAXTextStateChangeTypeSelectionMove;
161     case WebCore::AXTextStateChangeTypeSelectionExtend:
162         return kAXTextStateChangeTypeSelectionExtend;
163     case WebCore::AXTextStateChangeTypeSelectionBoundary:
164         return kAXTextStateChangeTypeSelectionBoundary;
165     }
166 }
167
168 static AXTextEditType platformEditTypeForWebCoreEditType(WebCore::AXTextEditType changeType)
169 {
170     switch (changeType) {
171     case WebCore::AXTextEditTypeUnknown:
172         return kAXTextEditTypeUnknown;
173     case WebCore::AXTextEditTypeDelete:
174         return kAXTextEditTypeDelete;
175     case WebCore::AXTextEditTypeInsert:
176         return kAXTextEditTypeInsert;
177     case WebCore::AXTextEditTypeTyping:
178         return kAXTextEditTypeTyping;
179     case WebCore::AXTextEditTypeDictation:
180         return kAXTextEditTypeDictation;
181     case WebCore::AXTextEditTypeCut:
182         return kAXTextEditTypeCut;
183     case WebCore::AXTextEditTypePaste:
184         return kAXTextEditTypePaste;
185     case WebCore::AXTextEditTypeAttributesChange:
186         return kAXTextEditTypeAttributesChange;
187     }
188 }
189
190 static AXTextSelectionDirection platformDirectionForWebCoreDirection(WebCore::AXTextSelectionDirection direction)
191 {
192     switch (direction) {
193     case WebCore::AXTextSelectionDirectionUnknown:
194         return kAXTextSelectionDirectionUnknown;
195     case WebCore::AXTextSelectionDirectionBeginning:
196         return kAXTextSelectionDirectionBeginning;
197     case WebCore::AXTextSelectionDirectionEnd:
198         return kAXTextSelectionDirectionEnd;
199     case WebCore::AXTextSelectionDirectionPrevious:
200         return kAXTextSelectionDirectionPrevious;
201     case WebCore::AXTextSelectionDirectionNext:
202         return kAXTextSelectionDirectionNext;
203     case WebCore::AXTextSelectionDirectionDiscontiguous:
204         return kAXTextSelectionDirectionDiscontiguous;
205     }
206 }
207
208 static AXTextSelectionGranularity platformGranularityForWebCoreGranularity(WebCore::AXTextSelectionGranularity granularity)
209 {
210     switch (granularity) {
211     case WebCore::AXTextSelectionGranularityUnknown:
212         return kAXTextSelectionGranularityUnknown;
213     case WebCore::AXTextSelectionGranularityCharacter:
214         return kAXTextSelectionGranularityCharacter;
215     case WebCore::AXTextSelectionGranularityWord:
216         return kAXTextSelectionGranularityWord;
217     case WebCore::AXTextSelectionGranularityLine:
218         return kAXTextSelectionGranularityLine;
219     case WebCore::AXTextSelectionGranularitySentence:
220         return kAXTextSelectionGranularitySentence;
221     case WebCore::AXTextSelectionGranularityParagraph:
222         return kAXTextSelectionGranularityParagraph;
223     case WebCore::AXTextSelectionGranularityPage:
224         return kAXTextSelectionGranularityPage;
225     case WebCore::AXTextSelectionGranularityDocument:
226         return kAXTextSelectionGranularityDocument;
227     case WebCore::AXTextSelectionGranularityAll:
228         return kAXTextSelectionGranularityAll;
229     }
230 }
231
232 // The simple Cocoa calls in this file don't throw exceptions.
233
234 namespace WebCore {
235
236 void AXObjectCache::attachWrapper(AXCoreObject* obj)
237 {
238     RetainPtr<WebAccessibilityObjectWrapper> wrapper = adoptNS([[WebAccessibilityObjectWrapper alloc] initWithAccessibilityObject:obj]);
239     obj->setWrapper(wrapper.get());
240 }
241
242 static BOOL axShouldRepostNotificationsForTests = false;
243
244 void AXObjectCache::setShouldRepostNotificationsForTests(bool value)
245 {
246     axShouldRepostNotificationsForTests = value;
247 }
248
249 static void AXPostNotificationWithUserInfo(AccessibilityObjectWrapper *object, NSString *notification, id userInfo, bool skipSystemNotification = false)
250 {
251     if (id associatedPluginParent = [object associatedPluginParent])
252         object = associatedPluginParent;
253
254     // 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
255     if (UNLIKELY(axShouldRepostNotificationsForTests))
256         [object accessibilityPostedNotification:notification userInfo:userInfo];
257
258     if (skipSystemNotification)
259         return;
260
261     NSAccessibilityPostNotificationWithUserInfo(object, notification, userInfo);
262 }
263
264 void AXObjectCache::postPlatformNotification(AXCoreObject* obj, AXNotification notification)
265 {
266     if (!obj)
267         return;
268
269     bool skipSystemNotification = false;
270     // Some notifications are unique to Safari and do not have NSAccessibility equivalents.
271     NSString *macNotification;
272     switch (notification) {
273         case AXActiveDescendantChanged:
274             // An active descendant change for trees means a selected rows change.
275             if (obj->isTree() || obj->isTable())
276                 macNotification = NSAccessibilitySelectedRowsChangedNotification;
277             
278             // When a combobox uses active descendant, it means the selected item in its associated
279             // list has changed. In these cases we should use selected children changed, because
280             // we don't want the focus to change away from the combobox where the user is typing.
281             else if (obj->isComboBox() || obj->isList() || obj->isListBox())
282                 macNotification = NSAccessibilitySelectedChildrenChangedNotification;
283             else
284                 macNotification = NSAccessibilityFocusedUIElementChangedNotification;                
285             break;
286         case AXAutocorrectionOccured:
287             macNotification = @"AXAutocorrectionOccurred";
288             break;
289         case AXFocusedUIElementChanged:
290             macNotification = NSAccessibilityFocusedUIElementChangedNotification;
291             break;
292         case AXLayoutComplete:
293             macNotification = @"AXLayoutComplete";
294             break;
295         case AXLoadComplete:
296             macNotification = @"AXLoadComplete";
297             // Frame loading events are handled by the UIProcess on macOS to improve reliability.
298             // On macOS, before notifications are allowed by AppKit to be sent to clients, you need to have a client (e.g. VoiceOver)
299             // register for that notification. Because these new processes appear before VO has a chance to register, it will often
300             // miss AXLoadComplete notifications. By moving them to the UIProcess, we can eliminate that issue.
301             skipSystemNotification = true;
302             break;
303         case AXInvalidStatusChanged:
304             macNotification = @"AXInvalidStatusChanged";
305             break;
306         case AXSelectedChildrenChanged:
307             if (obj->isTable() && obj->isExposable())
308                 macNotification = NSAccessibilitySelectedRowsChangedNotification;
309             else
310                 macNotification = NSAccessibilitySelectedChildrenChangedNotification;
311             break;
312         case AXSelectedTextChanged:
313             macNotification = NSAccessibilitySelectedTextChangedNotification;
314             break;
315         case AXCheckedStateChanged:
316         case AXValueChanged:
317             macNotification = NSAccessibilityValueChangedNotification;
318             break;
319         case AXLiveRegionCreated:
320             macNotification = NSAccessibilityLiveRegionCreatedNotification;
321             break;
322         case AXLiveRegionChanged:
323             macNotification = NSAccessibilityLiveRegionChangedNotification;
324             break;
325         case AXRowCountChanged:
326             macNotification = NSAccessibilityRowCountChangedNotification;
327             break;
328         case AXRowExpanded:
329             macNotification = NSAccessibilityRowExpandedNotification;
330             break;
331         case AXRowCollapsed:
332             macNotification = NSAccessibilityRowCollapsedNotification;
333             break;
334         case AXElementBusyChanged:
335             macNotification = @"AXElementBusyChanged";
336             break;
337         case AXExpandedChanged:
338             macNotification = @"AXExpandedChanged";
339             break;
340         case AXMenuClosed:
341             macNotification = (id)kAXMenuClosedNotification;
342             break;
343         case AXMenuListItemSelected:
344             macNotification = (id)kAXMenuItemSelectedNotification;
345             break;
346         case AXPressDidSucceed:
347             macNotification = @"AXPressDidSucceed";
348             break;
349         case AXPressDidFail:
350             macNotification = @"AXPressDidFail";
351             break;
352         case AXMenuOpened:
353             macNotification = (id)kAXMenuOpenedNotification;
354             break;
355         default:
356             return;
357     }
358     
359     // NSAccessibilityPostNotification will call this method, (but not when running DRT), so ASSERT here to make sure it does not crash.
360     // https://bugs.webkit.org/show_bug.cgi?id=46662
361     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
362     ASSERT([obj->wrapper() accessibilityIsIgnored] || true);
363     ALLOW_DEPRECATED_DECLARATIONS_END
364
365     AXPostNotificationWithUserInfo(obj->wrapper(), macNotification, nil, skipSystemNotification);
366 }
367
368 void AXObjectCache::postTextStateChangePlatformNotification(AXCoreObject* object, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
369 {
370     if (!object)
371         object = rootWebArea();
372
373     if (!object)
374         return;
375
376     NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:5];
377     if (m_isSynchronizingSelection)
378         [userInfo setObject:@YES forKey:NSAccessibilityTextStateSyncKey];
379     if (intent.type != AXTextStateChangeTypeUnknown) {
380         [userInfo setObject:@(platformChangeTypeForWebCoreChangeType(intent.type)) forKey:NSAccessibilityTextStateChangeTypeKey];
381         switch (intent.type) {
382         case AXTextStateChangeTypeSelectionMove:
383         case AXTextStateChangeTypeSelectionExtend:
384         case AXTextStateChangeTypeSelectionBoundary:
385             [userInfo setObject:@(platformDirectionForWebCoreDirection(intent.selection.direction)) forKey:NSAccessibilityTextSelectionDirection];
386             switch (intent.selection.direction) {
387             case AXTextSelectionDirectionUnknown:
388                 break;
389             case AXTextSelectionDirectionBeginning:
390             case AXTextSelectionDirectionEnd:
391             case AXTextSelectionDirectionPrevious:
392             case AXTextSelectionDirectionNext:
393                 [userInfo setObject:@(platformGranularityForWebCoreGranularity(intent.selection.granularity)) forKey:NSAccessibilityTextSelectionGranularity];
394                 break;
395             case AXTextSelectionDirectionDiscontiguous:
396                 break;
397             }
398             if (intent.selection.focusChange)
399                 [userInfo setObject:@(intent.selection.focusChange) forKey:NSAccessibilityTextSelectionChangedFocus];
400             break;
401         case AXTextStateChangeTypeUnknown:
402         case AXTextStateChangeTypeEdit:
403             break;
404         }
405     }
406     if (!selection.isNone()) {
407         if (id textMarkerRange = textMarkerRangeFromVisiblePositions(this, selection.visibleStart(), selection.visibleEnd()))
408             [userInfo setObject:textMarkerRange forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
409     }
410
411     if (id wrapper = object->wrapper())
412         [userInfo setObject:wrapper forKey:NSAccessibilityTextChangeElement];
413
414     if (auto root = rootWebArea()) {
415         AXPostNotificationWithUserInfo(rootWebArea()->wrapper(), NSAccessibilitySelectedTextChangedNotification, userInfo);
416         if (root->wrapper() != object->wrapper())
417             AXPostNotificationWithUserInfo(object->wrapper(), NSAccessibilitySelectedTextChangedNotification, userInfo);
418     }
419
420     [userInfo release];
421 }
422
423 static void addTextMarkerFor(NSMutableDictionary* change, AXCoreObject& object, const VisiblePosition& position)
424 {
425     if (position.isNull())
426         return;
427     if (id textMarker = [object.wrapper() textMarkerForVisiblePosition:position])
428         [change setObject:textMarker forKey:NSAccessibilityTextChangeValueStartMarker];
429 }
430
431 static void addTextMarkerFor(NSMutableDictionary* change, AXCoreObject& object, HTMLTextFormControlElement& textControl)
432 {
433     if (id textMarker = [object.wrapper() textMarkerForFirstPositionInTextControl:textControl])
434         [change setObject:textMarker forKey:NSAccessibilityTextChangeValueStartMarker];
435 }
436
437 template <typename TextMarkerTargetType>
438 static NSDictionary *textReplacementChangeDictionary(AXCoreObject& object, AXTextEditType type, const String& string, TextMarkerTargetType& markerTarget)
439 {
440     NSString *text = (NSString *)string;
441     NSUInteger length = [text length];
442     if (!length)
443         return nil;
444     NSMutableDictionary *change = [[NSMutableDictionary alloc] initWithCapacity:4];
445     [change setObject:@(platformEditTypeForWebCoreEditType(type)) forKey:NSAccessibilityTextEditType];
446     if (length > AXValueChangeTruncationLength) {
447         [change setObject:[NSNumber numberWithInt:length] forKey:NSAccessibilityTextChangeValueLength];
448         text = [text substringToIndex:AXValueChangeTruncationLength];
449     }
450     [change setObject:text forKey:NSAccessibilityTextChangeValue];
451     addTextMarkerFor(change, object, markerTarget);
452     return [change autorelease];
453 }
454
455 void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject* object, AXTextEditType type, const String& text, const VisiblePosition& position)
456 {
457     if (!text.length())
458         return;
459
460     postTextReplacementPlatformNotification(object, AXTextEditTypeUnknown, emptyString(), type, text, position);
461 }
462
463 static void postUserInfoForChanges(AXCoreObject& rootWebArea, AXCoreObject& object, NSMutableArray* changes)
464 {
465     NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithCapacity:4];
466     [userInfo setObject:@(platformChangeTypeForWebCoreChangeType(AXTextStateChangeTypeEdit)) forKey:NSAccessibilityTextStateChangeTypeKey];
467     if (changes.count)
468         [userInfo setObject:changes forKey:NSAccessibilityTextChangeValues];
469
470     if (id wrapper = object.wrapper())
471         [userInfo setObject:wrapper forKey:NSAccessibilityTextChangeElement];
472
473     AXPostNotificationWithUserInfo(rootWebArea.wrapper(), NSAccessibilityValueChangedNotification, userInfo);
474     if (rootWebArea.wrapper() != object.wrapper())
475         AXPostNotificationWithUserInfo(object.wrapper(), NSAccessibilityValueChangedNotification, userInfo);
476
477     [userInfo release];
478 }
479
480 void AXObjectCache::postTextReplacementPlatformNotification(AXCoreObject* object, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition& position)
481 {
482     if (!object)
483         object = rootWebArea();
484
485     if (!object)
486         return;
487
488     NSMutableArray *changes = [[NSMutableArray alloc] initWithCapacity:2];
489     if (NSDictionary *change = textReplacementChangeDictionary(*object, deletionType, deletedText, position))
490         [changes addObject:change];
491     if (NSDictionary *change = textReplacementChangeDictionary(*object, insertionType, insertedText, position))
492         [changes addObject:change];
493
494     if (auto* root = rootWebArea())
495         postUserInfoForChanges(*root, *object, changes);
496     [changes release];
497 }
498
499 void AXObjectCache::postTextReplacementPlatformNotificationForTextControl(AXCoreObject* object, const String& deletedText, const String& insertedText, HTMLTextFormControlElement& textControl)
500 {
501     if (!object)
502         object = rootWebArea();
503
504     if (!object)
505         return;
506
507     NSMutableArray *changes = [[NSMutableArray alloc] initWithCapacity:2];
508     if (NSDictionary *change = textReplacementChangeDictionary(*object, AXTextEditTypeDelete, deletedText, textControl))
509         [changes addObject:change];
510     if (NSDictionary *change = textReplacementChangeDictionary(*object, AXTextEditTypeInsert, insertedText, textControl))
511         [changes addObject:change];
512
513     if (auto* root = rootWebArea())
514         postUserInfoForChanges(*root, *object, changes);
515     [changes release];
516 }
517
518 void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject* axFrameObject, AXLoadingEvent loadingEvent)
519 {
520     if (!axFrameObject)
521         return;
522     
523     if (loadingEvent == AXLoadingFinished && axFrameObject->document() == axFrameObject->topDocument())
524         postPlatformNotification(axFrameObject, AXLoadComplete);
525 }
526
527 void AXObjectCache::platformHandleFocusedUIElementChanged(Node*, Node*)
528 {
529     NSAccessibilityHandleFocusChanged();
530     // AXFocusChanged is a test specific notification name and not something a real AT will be listening for
531     if (UNLIKELY(!axShouldRepostNotificationsForTests))
532         return;
533
534     auto* rootWebArea = this->rootWebArea();
535     if (!rootWebArea)
536         return;
537
538     [rootWebArea->wrapper() accessibilityPostedNotification:@"AXFocusChanged" userInfo:nil];
539 }
540
541 void AXObjectCache::handleScrolledToAnchor(const Node*)
542 {
543 }
544
545 void AXObjectCache::platformPerformDeferredCacheUpdate()
546 {
547 }
548
549 // TextMarker utility functions.
550
551 static id AXTextMarkerRange(id startMarker, id endMarker)
552 {
553     ASSERT(startMarker);
554     ASSERT(endMarker);
555     ASSERT(CFGetTypeID((__bridge CFTypeRef)startMarker) == AXTextMarkerGetTypeID());
556     ASSERT(CFGetTypeID((__bridge CFTypeRef)endMarker) == AXTextMarkerGetTypeID());
557     return CFBridgingRelease(AXTextMarkerRangeCreate(kCFAllocatorDefault, (AXTextMarkerRef)startMarker, (AXTextMarkerRef)endMarker));
558 }
559
560 id textMarkerRangeFromMarkers(id textMarker1, id textMarker2)
561 {
562     if (!textMarker1 || !textMarker2)
563         return nil;
564
565     return AXTextMarkerRange(textMarker1, textMarker2);
566 }
567
568 id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
569 {
570     ASSERT(cache);
571     if (!cache)
572         return nil;
573
574     auto textMarkerData = cache->textMarkerDataForVisiblePosition(visiblePos);
575     if (!textMarkerData)
576         return nil;
577
578     return CFBridgingRelease(AXTextMarkerCreate(kCFAllocatorDefault, (const UInt8*)&textMarkerData.value(), sizeof(textMarkerData.value())));
579 }
580
581 id textMarkerRangeFromVisiblePositions(AXObjectCache* cache, const VisiblePosition& startPosition, const VisiblePosition& endPosition)
582 {
583     if (!cache)
584         return nil;
585
586     id startTextMarker = textMarkerForVisiblePosition(cache, startPosition);
587     id endTextMarker = textMarkerForVisiblePosition(cache, endPosition);
588     return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
589 }
590
591 }
592
593 #endif // ENABLE(ACCESSIBILITY) && PLATFORM(MAC)