[WebAccessibilityObjectWrapper detach] should detach either the wrapped AXObject...
[WebKit-https.git] / Source / WebCore / accessibility / mac / WebAccessibilityObjectWrapperBase.mm
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2011 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "config.h"
30 #import "WebAccessibilityObjectWrapperBase.h"
31
32 #if ENABLE(ACCESSIBILITY)
33
34 #import "AXObjectCache.h"
35 #import "AccessibilityARIAGridRow.h"
36 #import "AccessibilityList.h"
37 #import "AccessibilityListBox.h"
38 #import "AccessibilityObjectInterface.h"
39 #import "AccessibilityRenderObject.h"
40 #import "AccessibilityScrollView.h"
41 #import "AccessibilitySpinButton.h"
42 #import "AccessibilityTable.h"
43 #import "AccessibilityTableCell.h"
44 #import "AccessibilityTableColumn.h"
45 #import "AccessibilityTableRow.h"
46 #import "Chrome.h"
47 #import "ChromeClient.h"
48 #import "ColorMac.h"
49 #import "ContextMenuController.h"
50 #import "Editing.h"
51 #import "Font.h"
52 #import "FontCascade.h"
53 #import "Frame.h"
54 #import "FrameLoaderClient.h"
55 #import "FrameSelection.h"
56 #import "HTMLNames.h"
57 #import "LayoutRect.h"
58 #import "LocalizedStrings.h"
59 #import "Page.h"
60 #import "RenderTextControl.h"
61 #import "RenderView.h"
62 #import "RenderWidget.h"
63 #import "ScrollView.h"
64 #import "TextCheckerClient.h"
65 #import "TextCheckingHelper.h"
66 #import "VisibleUnits.h"
67 #import "WebCoreFrameView.h"
68
69 #if PLATFORM(MAC)
70 #import <pal/spi/mac/HIServicesSPI.h>
71 #else
72 #import "WAKView.h"
73 #import "WAKWindow.h"
74 #endif
75
76 using namespace WebCore;
77 using namespace HTMLNames;
78
79 // Search Keys
80 #ifndef NSAccessibilityAnyTypeSearchKey
81 #define NSAccessibilityAnyTypeSearchKey @"AXAnyTypeSearchKey"
82 #endif
83
84 #ifndef NSAccessibilityArticleSearchKey
85 #define NSAccessibilityArticleSearchKey @"AXArticleSearchKey"
86 #endif
87
88 #ifndef NSAccessibilityBlockquoteSameLevelSearchKey
89 #define NSAccessibilityBlockquoteSameLevelSearchKey @"AXBlockquoteSameLevelSearchKey"
90 #endif
91
92 #ifndef NSAccessibilityBlockquoteSearchKey
93 #define NSAccessibilityBlockquoteSearchKey @"AXBlockquoteSearchKey"
94 #endif
95
96 #ifndef NSAccessibilityBoldFontSearchKey
97 #define NSAccessibilityBoldFontSearchKey @"AXBoldFontSearchKey"
98 #endif
99
100 #ifndef NSAccessibilityButtonSearchKey
101 #define NSAccessibilityButtonSearchKey @"AXButtonSearchKey"
102 #endif
103
104 #ifndef NSAccessibilityCheckBoxSearchKey
105 #define NSAccessibilityCheckBoxSearchKey @"AXCheckBoxSearchKey"
106 #endif
107
108 #ifndef NSAccessibilityControlSearchKey
109 #define NSAccessibilityControlSearchKey @"AXControlSearchKey"
110 #endif
111
112 #ifndef NSAccessibilityDifferentTypeSearchKey
113 #define NSAccessibilityDifferentTypeSearchKey @"AXDifferentTypeSearchKey"
114 #endif
115
116 #ifndef NSAccessibilityFontChangeSearchKey
117 #define NSAccessibilityFontChangeSearchKey @"AXFontChangeSearchKey"
118 #endif
119
120 #ifndef NSAccessibilityFontColorChangeSearchKey
121 #define NSAccessibilityFontColorChangeSearchKey @"AXFontColorChangeSearchKey"
122 #endif
123
124 #ifndef NSAccessibilityFrameSearchKey
125 #define NSAccessibilityFrameSearchKey @"AXFrameSearchKey"
126 #endif
127
128 #ifndef NSAccessibilityGraphicSearchKey
129 #define NSAccessibilityGraphicSearchKey @"AXGraphicSearchKey"
130 #endif
131
132 #ifndef NSAccessibilityHeadingLevel1SearchKey
133 #define NSAccessibilityHeadingLevel1SearchKey @"AXHeadingLevel1SearchKey"
134 #endif
135
136 #ifndef NSAccessibilityHeadingLevel2SearchKey
137 #define NSAccessibilityHeadingLevel2SearchKey @"AXHeadingLevel2SearchKey"
138 #endif
139
140 #ifndef NSAccessibilityHeadingLevel3SearchKey
141 #define NSAccessibilityHeadingLevel3SearchKey @"AXHeadingLevel3SearchKey"
142 #endif
143
144 #ifndef NSAccessibilityHeadingLevel4SearchKey
145 #define NSAccessibilityHeadingLevel4SearchKey @"AXHeadingLevel4SearchKey"
146 #endif
147
148 #ifndef NSAccessibilityHeadingLevel5SearchKey
149 #define NSAccessibilityHeadingLevel5SearchKey @"AXHeadingLevel5SearchKey"
150 #endif
151
152 #ifndef NSAccessibilityHeadingLevel6SearchKey
153 #define NSAccessibilityHeadingLevel6SearchKey @"AXHeadingLevel6SearchKey"
154 #endif
155
156 #ifndef NSAccessibilityHeadingSameLevelSearchKey
157 #define NSAccessibilityHeadingSameLevelSearchKey @"AXHeadingSameLevelSearchKey"
158 #endif
159
160 #ifndef NSAccessibilityHeadingSearchKey
161 #define NSAccessibilityHeadingSearchKey @"AXHeadingSearchKey"
162 #endif
163
164 #ifndef NSAccessibilityHighlightedSearchKey
165 #define NSAccessibilityHighlightedSearchKey @"AXHighlightedSearchKey"
166 #endif
167
168 #ifndef NSAccessibilityKeyboardFocusableSearchKey
169 #define NSAccessibilityKeyboardFocusableSearchKey @"AXKeyboardFocusableSearchKey"
170 #endif
171
172 #ifndef NSAccessibilityItalicFontSearchKey
173 #define NSAccessibilityItalicFontSearchKey @"AXItalicFontSearchKey"
174 #endif
175
176 #ifndef NSAccessibilityLandmarkSearchKey
177 #define NSAccessibilityLandmarkSearchKey @"AXLandmarkSearchKey"
178 #endif
179
180 #ifndef NSAccessibilityLinkSearchKey
181 #define NSAccessibilityLinkSearchKey @"AXLinkSearchKey"
182 #endif
183
184 #ifndef NSAccessibilityListSearchKey
185 #define NSAccessibilityListSearchKey @"AXListSearchKey"
186 #endif
187
188 #ifndef NSAccessibilityLiveRegionSearchKey
189 #define NSAccessibilityLiveRegionSearchKey @"AXLiveRegionSearchKey"
190 #endif
191
192 #ifndef NSAccessibilityMisspelledWordSearchKey
193 #define NSAccessibilityMisspelledWordSearchKey @"AXMisspelledWordSearchKey"
194 #endif
195
196 #ifndef NSAccessibilityOutlineSearchKey
197 #define NSAccessibilityOutlineSearchKey @"AXOutlineSearchKey"
198 #endif
199
200 #ifndef NSAccessibilityPlainTextSearchKey
201 #define NSAccessibilityPlainTextSearchKey @"AXPlainTextSearchKey"
202 #endif
203
204 #ifndef NSAccessibilityRadioGroupSearchKey
205 #define NSAccessibilityRadioGroupSearchKey @"AXRadioGroupSearchKey"
206 #endif
207
208 #ifndef NSAccessibilitySameTypeSearchKey
209 #define NSAccessibilitySameTypeSearchKey @"AXSameTypeSearchKey"
210 #endif
211
212 #ifndef NSAccessibilityStaticTextSearchKey
213 #define NSAccessibilityStaticTextSearchKey @"AXStaticTextSearchKey"
214 #endif
215
216 #ifndef NSAccessibilityStyleChangeSearchKey
217 #define NSAccessibilityStyleChangeSearchKey @"AXStyleChangeSearchKey"
218 #endif
219
220 #ifndef NSAccessibilityTableSameLevelSearchKey
221 #define NSAccessibilityTableSameLevelSearchKey @"AXTableSameLevelSearchKey"
222 #endif
223
224 #ifndef NSAccessibilityTableSearchKey
225 #define NSAccessibilityTableSearchKey @"AXTableSearchKey"
226 #endif
227
228 #ifndef NSAccessibilityTextFieldSearchKey
229 #define NSAccessibilityTextFieldSearchKey @"AXTextFieldSearchKey"
230 #endif
231
232 #ifndef NSAccessibilityUnderlineSearchKey
233 #define NSAccessibilityUnderlineSearchKey @"AXUnderlineSearchKey"
234 #endif
235
236 #ifndef NSAccessibilityUnvisitedLinkSearchKey
237 #define NSAccessibilityUnvisitedLinkSearchKey @"AXUnvisitedLinkSearchKey"
238 #endif
239
240 #ifndef NSAccessibilityVisitedLinkSearchKey
241 #define NSAccessibilityVisitedLinkSearchKey @"AXVisitedLinkSearchKey"
242 #endif
243
244 // Search
245 #ifndef NSAccessibilityImmediateDescendantsOnly
246 #define NSAccessibilityImmediateDescendantsOnly @"AXImmediateDescendantsOnly"
247 #endif
248
249 static NSArray *convertMathPairsToNSArray(const AccessibilityObject::AccessibilityMathMultiscriptPairs& pairs, NSString *subscriptKey, NSString *superscriptKey)
250 {
251     NSMutableArray *array = [NSMutableArray arrayWithCapacity:pairs.size()];
252     for (const auto& pair : pairs) {
253         NSMutableDictionary *pairDictionary = [NSMutableDictionary dictionary];
254         if (pair.first && pair.first->wrapper() && !pair.first->accessibilityIsIgnored())
255             [pairDictionary setObject:pair.first->wrapper() forKey:subscriptKey];
256         if (pair.second && pair.second->wrapper() && !pair.second->accessibilityIsIgnored())
257             [pairDictionary setObject:pair.second->wrapper() forKey:superscriptKey];
258         [array addObject:pairDictionary];
259     }
260     return array;
261 }
262
263 static void addChildToArray(AXCoreObject& child, RetainPtr<NSMutableArray> array)
264 {
265     WebAccessibilityObjectWrapper *wrapper = child.wrapper();
266     // We want to return the attachment view instead of the object representing the attachment,
267     // otherwise, we get palindrome errors in the AX hierarchy.
268     if (child.isAttachment() && [wrapper attachmentView])
269         [array.get() addObject:[wrapper attachmentView]];
270     else if (wrapper)
271         [array.get() addObject:wrapper];
272 }
273
274 NSArray *convertToNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector& children)
275 {
276     NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:children.size()];
277     for (const auto& child : children)
278         addChildToArray(*child, result);
279     return [result autorelease];
280 }
281
282 @implementation WebAccessibilityObjectWrapperBase
283
284 @synthesize identifier=_identifier;
285
286 - (id)initWithAccessibilityObject:(AXCoreObject*)axObject
287 {
288     if (!(self = [super init]))
289         return nil;
290
291     [self attachAXObject:axObject];
292     return self;
293 }
294
295 - (void)attachAXObject:(AXCoreObject*)axObject
296 {
297     ASSERT(axObject && (_identifier == InvalidAXID || _identifier == axObject->objectID()));
298     m_axObject = axObject;
299     if (_identifier == InvalidAXID)
300         _identifier = m_axObject->objectID();
301 }
302
303 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
304 - (void)attachIsolatedObject:(AXCoreObject*)isolatedObject
305 {
306     ASSERT(isolatedObject && (_identifier == InvalidAXID || _identifier == isolatedObject->objectID()));
307     m_isolatedObject = isolatedObject;
308     if (_identifier == InvalidAXID)
309         _identifier = m_isolatedObject->objectID();
310 }
311 #endif
312
313 - (void)detachAXObject
314 {
315     m_axObject = nullptr;
316 }
317
318 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
319 - (void)detachIsolatedObject
320 {
321     m_isolatedObject = nullptr;
322 }
323 #endif
324
325 - (void)detach
326 {
327     _identifier = InvalidAXID;
328 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
329     if (!isMainThread()) {
330         ASSERT(AXObjectCache::clientSupportsIsolatedTree());
331         [self detachIsolatedObject];
332         return;
333     }
334 #endif
335     [self detachAXObject];
336 }
337
338 - (BOOL)updateObjectBackingStore
339 {
340     // Calling updateBackingStore() can invalidate this element so self must be retained.
341     // If it does become invalidated, self.axBackingObject will be nil.
342     CFRetain((__bridge CFTypeRef)self);
343     CFAutorelease((__bridge CFTypeRef)self);
344
345     if (!self.axBackingObject)
346         return NO;
347     
348     self.axBackingObject->updateBackingStore();
349     if (!self.axBackingObject)
350         return NO;
351     
352     return YES;
353 }
354
355 - (id)attachmentView
356 {
357     return nil;
358 }
359
360 // This should be the "visible" text that's actually on the screen if possible.
361 // If there's alternative text, that can override the title.
362 - (NSString *)baseAccessibilityTitle
363 {
364     return self.axBackingObject->titleAttributeValue();
365 }
366
367 - (WebCore::AXCoreObject*)axBackingObject
368 {
369 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
370     if (!isMainThread()) {
371         ASSERT(AXObjectCache::clientSupportsIsolatedTree());
372         return m_isolatedObject;
373     }
374 #endif
375     return m_axObject;
376 }
377
378 - (NSString *)baseAccessibilityDescription
379 {
380     return self.axBackingObject->descriptionAttributeValue();
381 }
382
383 - (NSArray<NSString *> *)baseAccessibilitySpeechHint
384 {
385     return [(NSString *)self.axBackingObject->speechHintAttributeValue() componentsSeparatedByString:@" "];
386 }
387
388 - (NSString *)baseAccessibilityHelpText
389 {
390     return self.axBackingObject->helpTextAttributeValue();
391 }
392
393 struct PathConversionInfo {
394     WebAccessibilityObjectWrapperBase *wrapper;
395     CGMutablePathRef path;
396 };
397
398 static void convertPathToScreenSpaceFunction(PathConversionInfo& conversion, const PathElement& element)
399 {
400     WebAccessibilityObjectWrapperBase *wrapper = conversion.wrapper;
401     CGMutablePathRef newPath = conversion.path;
402     FloatRect rect;
403     switch (element.type) {
404     case PathElement::Type::MoveToPoint:
405     {
406         rect = FloatRect(element.points[0], FloatSize());
407         CGPoint newPoint = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
408         CGPathMoveToPoint(newPath, nil, newPoint.x, newPoint.y);
409         break;
410     }
411     case PathElement::Type::AddLineToPoint:
412     {
413         rect = FloatRect(element.points[0], FloatSize());
414         CGPoint newPoint = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
415         CGPathAddLineToPoint(newPath, nil, newPoint.x, newPoint.y);
416         break;
417     }
418     case PathElement::Type::AddQuadCurveToPoint:
419     {
420         rect = FloatRect(element.points[0], FloatSize());
421         CGPoint newPoint1 = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
422
423         rect = FloatRect(element.points[1], FloatSize());
424         CGPoint newPoint2 = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
425         CGPathAddQuadCurveToPoint(newPath, nil, newPoint1.x, newPoint1.y, newPoint2.x, newPoint2.y);
426         break;
427     }
428     case PathElement::Type::AddCurveToPoint:
429     {
430         rect = FloatRect(element.points[0], FloatSize());
431         CGPoint newPoint1 = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
432
433         rect = FloatRect(element.points[1], FloatSize());
434         CGPoint newPoint2 = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
435
436         rect = FloatRect(element.points[2], FloatSize());
437         CGPoint newPoint3 = [wrapper convertRectToSpace:rect space:AccessibilityConversionSpace::Screen].origin;
438         CGPathAddCurveToPoint(newPath, nil, newPoint1.x, newPoint1.y, newPoint2.x, newPoint2.y, newPoint3.x, newPoint3.y);
439         break;
440     }
441     case PathElement::Type::CloseSubpath:
442     {
443         CGPathCloseSubpath(newPath);
444         break;
445     }
446     }
447 }
448
449 - (CGPathRef)convertPathToScreenSpace:(Path &)path
450 {
451     PathConversionInfo conversion = { self, CGPathCreateMutable() };
452     path.apply([&conversion](const PathElement& pathElement) {
453         convertPathToScreenSpaceFunction(conversion, pathElement);
454     });
455     CFAutorelease(conversion.path);
456     return conversion.path;
457 }
458
459 - (id)_accessibilityWebDocumentView
460 {
461     ASSERT_NOT_REACHED();
462     // Overridden by sub-classes
463     return nil;
464 }
465
466 - (CGRect)convertRectToSpace:(WebCore::FloatRect &)rect space:(AccessibilityConversionSpace)space
467 {
468     if (!self.axBackingObject)
469         return CGRectZero;
470     
471     CGSize size = CGSizeMake(rect.size().width(), rect.size().height());
472     CGPoint point = CGPointMake(rect.x(), rect.y());
473     
474     CGRect cgRect = CGRectMake(point.x, point.y, size.width, size.height);
475
476     // WebKit1 code path... platformWidget() exists.
477     FrameView* frameView = self.axBackingObject->documentFrameView();
478 #if PLATFORM(IOS_FAMILY)
479     WAKView* documentView = frameView ? frameView->documentView() : nullptr;
480     if (documentView) {
481         cgRect = [documentView convertRect:cgRect toView:nil];
482         
483         // we need the web document view to give us our final screen coordinates
484         // because that can take account of the scroller
485         id webDocument = [self _accessibilityWebDocumentView];
486         if (webDocument)
487             cgRect = [webDocument convertRect:cgRect toView:nil];
488         return cgRect;
489     }
490 #else
491     if (frameView && frameView->platformWidget()) {
492         NSRect nsRect = NSRectFromCGRect(cgRect);
493         NSView* view = frameView->documentView();
494         ALLOW_DEPRECATED_DECLARATIONS_BEGIN
495         nsRect = [[view window] convertRectToScreen:[view convertRect:nsRect toView:nil]];
496         ALLOW_DEPRECATED_DECLARATIONS_END
497         return NSRectToCGRect(nsRect);
498     }
499 #endif
500     else
501         return static_cast<CGRect>(self.axBackingObject->convertFrameToSpace(rect, space));
502 }
503
504 - (NSString *)ariaLandmarkRoleDescription
505 {
506     return self.axBackingObject->ariaLandmarkRoleDescription();
507 }
508
509 - (void)baseAccessibilitySetFocus:(BOOL)focus
510 {
511     // If focus is just set without making the view the first responder, then keyboard focus won't move to the right place.
512     if (focus && !self.axBackingObject->document()->frame()->selection().isFocusedAndActive()) {
513         FrameView* frameView = self.axBackingObject->documentFrameView();
514         Page* page = self.axBackingObject->page();
515         if (page && frameView) {
516             ChromeClient& chromeClient = page->chrome().client();
517             chromeClient.focus();
518
519             // Legacy WebKit1 case.
520             if (frameView->platformWidget())
521                 chromeClient.makeFirstResponder(frameView->platformWidget());
522             else
523                 chromeClient.assistiveTechnologyMakeFirstResponder();
524         }
525     }
526
527     self.axBackingObject->setFocused(focus);
528 }
529
530 - (NSString *)accessibilityPlatformMathSubscriptKey
531 {
532     ASSERT_NOT_REACHED();
533     return nil;
534 }
535
536 - (NSString *)accessibilityPlatformMathSuperscriptKey
537 {
538     ASSERT_NOT_REACHED();
539     return nil;    
540 }
541
542 - (NSArray *)accessibilityMathPostscriptPairs
543 {
544     AccessibilityObject::AccessibilityMathMultiscriptPairs pairs;
545     self.axBackingObject->mathPostscripts(pairs);
546     return convertMathPairsToNSArray(pairs, [self accessibilityPlatformMathSubscriptKey], [self accessibilityPlatformMathSuperscriptKey]);
547 }
548
549 - (NSArray *)accessibilityMathPrescriptPairs
550 {
551     AccessibilityObject::AccessibilityMathMultiscriptPairs pairs;
552     self.axBackingObject->mathPrescripts(pairs);
553     return convertMathPairsToNSArray(pairs, [self accessibilityPlatformMathSubscriptKey], [self accessibilityPlatformMathSuperscriptKey]);
554 }
555
556 // This is set by DRT when it wants to listen for notifications.
557 static BOOL accessibilityShouldRepostNotifications;
558 + (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
559 {
560     accessibilityShouldRepostNotifications = repost;
561 #if PLATFORM(MAC)
562     AXObjectCache::setShouldRepostNotificationsForTests(repost);
563 #endif
564 }
565
566 - (void)accessibilityPostedNotification:(NSString *)notificationName
567 {
568     if (accessibilityShouldRepostNotifications)
569         [self accessibilityPostedNotification:notificationName userInfo:nil];
570 }
571
572 static bool isValueTypeSupported(id value)
573 {
574     return [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[WebAccessibilityObjectWrapperBase class]];
575 }
576
577 static NSArray *arrayRemovingNonSupportedTypes(NSArray *array)
578 {
579     ASSERT([array isKindOfClass:[NSArray class]]);
580     NSMutableArray *mutableArray = [array mutableCopy];
581     for (NSUInteger i = 0; i < [mutableArray count];) {
582         id value = [mutableArray objectAtIndex:i];
583         if ([value isKindOfClass:[NSDictionary class]])
584             [mutableArray replaceObjectAtIndex:i withObject:dictionaryRemovingNonSupportedTypes(value)];
585         else if ([value isKindOfClass:[NSArray class]])
586             [mutableArray replaceObjectAtIndex:i withObject:arrayRemovingNonSupportedTypes(value)];
587         else if (!isValueTypeSupported(value)) {
588             [mutableArray removeObjectAtIndex:i];
589             continue;
590         }
591         i++;
592     }
593     return [mutableArray autorelease];
594 }
595
596 static NSDictionary *dictionaryRemovingNonSupportedTypes(NSDictionary *dictionary)
597 {
598     if (!dictionary)
599         return nil;
600     ASSERT([dictionary isKindOfClass:[NSDictionary class]]);
601     NSMutableDictionary *mutableDictionary = [dictionary mutableCopy];
602     for (NSString *key in dictionary) {
603         id value = [dictionary objectForKey:key];
604         if ([value isKindOfClass:[NSDictionary class]])
605             [mutableDictionary setObject:dictionaryRemovingNonSupportedTypes(value) forKey:key];
606         else if ([value isKindOfClass:[NSArray class]])
607             [mutableDictionary setObject:arrayRemovingNonSupportedTypes(value) forKey:key];
608         else if (!isValueTypeSupported(value))
609             [mutableDictionary removeObjectForKey:key];
610     }
611     return [mutableDictionary autorelease];
612 }
613
614 - (void)accessibilityPostedNotification:(NSString *)notificationName userInfo:(NSDictionary *)userInfo
615 {
616     if (accessibilityShouldRepostNotifications) {
617         ASSERT(notificationName);
618         userInfo = dictionaryRemovingNonSupportedTypes(userInfo);
619         NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", userInfo, @"userInfo", nil];
620         [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:self userInfo:info];
621     }
622 }
623
624 #pragma mark Search helpers
625
626 typedef HashMap<String, AccessibilitySearchKey> AccessibilitySearchKeyMap;
627
628 struct SearchKeyEntry {
629     String key;
630     AccessibilitySearchKey value;
631 };
632
633 static AccessibilitySearchKeyMap* createAccessibilitySearchKeyMap()
634 {
635     const SearchKeyEntry searchKeys[] = {
636         { NSAccessibilityAnyTypeSearchKey, AccessibilitySearchKey::AnyType },
637         { NSAccessibilityArticleSearchKey, AccessibilitySearchKey::Article },
638         { NSAccessibilityBlockquoteSameLevelSearchKey, AccessibilitySearchKey::BlockquoteSameLevel },
639         { NSAccessibilityBlockquoteSearchKey, AccessibilitySearchKey::Blockquote },
640         { NSAccessibilityBoldFontSearchKey, AccessibilitySearchKey::BoldFont },
641         { NSAccessibilityButtonSearchKey, AccessibilitySearchKey::Button },
642         { NSAccessibilityCheckBoxSearchKey, AccessibilitySearchKey::CheckBox },
643         { NSAccessibilityControlSearchKey, AccessibilitySearchKey::Control },
644         { NSAccessibilityDifferentTypeSearchKey, AccessibilitySearchKey::DifferentType },
645         { NSAccessibilityFontChangeSearchKey, AccessibilitySearchKey::FontChange },
646         { NSAccessibilityFontColorChangeSearchKey, AccessibilitySearchKey::FontColorChange },
647         { NSAccessibilityFrameSearchKey, AccessibilitySearchKey::Frame },
648         { NSAccessibilityGraphicSearchKey, AccessibilitySearchKey::Graphic },
649         { NSAccessibilityHeadingLevel1SearchKey, AccessibilitySearchKey::HeadingLevel1 },
650         { NSAccessibilityHeadingLevel2SearchKey, AccessibilitySearchKey::HeadingLevel2 },
651         { NSAccessibilityHeadingLevel3SearchKey, AccessibilitySearchKey::HeadingLevel3 },
652         { NSAccessibilityHeadingLevel4SearchKey, AccessibilitySearchKey::HeadingLevel4 },
653         { NSAccessibilityHeadingLevel5SearchKey, AccessibilitySearchKey::HeadingLevel5 },
654         { NSAccessibilityHeadingLevel6SearchKey, AccessibilitySearchKey::HeadingLevel6 },
655         { NSAccessibilityHeadingSameLevelSearchKey, AccessibilitySearchKey::HeadingSameLevel },
656         { NSAccessibilityHeadingSearchKey, AccessibilitySearchKey::Heading },
657         { NSAccessibilityHighlightedSearchKey, AccessibilitySearchKey::Highlighted },
658         { NSAccessibilityKeyboardFocusableSearchKey, AccessibilitySearchKey::KeyboardFocusable },
659         { NSAccessibilityItalicFontSearchKey, AccessibilitySearchKey::ItalicFont },
660         { NSAccessibilityLandmarkSearchKey, AccessibilitySearchKey::Landmark },
661         { NSAccessibilityLinkSearchKey, AccessibilitySearchKey::Link },
662         { NSAccessibilityListSearchKey, AccessibilitySearchKey::List },
663         { NSAccessibilityLiveRegionSearchKey, AccessibilitySearchKey::LiveRegion },
664         { NSAccessibilityMisspelledWordSearchKey, AccessibilitySearchKey::MisspelledWord },
665         { NSAccessibilityOutlineSearchKey, AccessibilitySearchKey::Outline },
666         { NSAccessibilityPlainTextSearchKey, AccessibilitySearchKey::PlainText },
667         { NSAccessibilityRadioGroupSearchKey, AccessibilitySearchKey::RadioGroup },
668         { NSAccessibilitySameTypeSearchKey, AccessibilitySearchKey::SameType },
669         { NSAccessibilityStaticTextSearchKey, AccessibilitySearchKey::StaticText },
670         { NSAccessibilityStyleChangeSearchKey, AccessibilitySearchKey::StyleChange },
671         { NSAccessibilityTableSameLevelSearchKey, AccessibilitySearchKey::TableSameLevel },
672         { NSAccessibilityTableSearchKey, AccessibilitySearchKey::Table },
673         { NSAccessibilityTextFieldSearchKey, AccessibilitySearchKey::TextField },
674         { NSAccessibilityUnderlineSearchKey, AccessibilitySearchKey::Underline },
675         { NSAccessibilityUnvisitedLinkSearchKey, AccessibilitySearchKey::UnvisitedLink },
676         { NSAccessibilityVisitedLinkSearchKey, AccessibilitySearchKey::VisitedLink }
677     };
678     
679     AccessibilitySearchKeyMap* searchKeyMap = new AccessibilitySearchKeyMap;
680     for (size_t i = 0; i < WTF_ARRAY_LENGTH(searchKeys); i++)
681         searchKeyMap->set(searchKeys[i].key, searchKeys[i].value);
682     
683     return searchKeyMap;
684 }
685
686 static AccessibilitySearchKey accessibilitySearchKeyForString(const String& value)
687 {
688     if (value.isEmpty())
689         return AccessibilitySearchKey::AnyType;
690     
691     static const AccessibilitySearchKeyMap* searchKeyMap = createAccessibilitySearchKeyMap();
692     AccessibilitySearchKey searchKey = searchKeyMap->get(value);    
693     return static_cast<int>(searchKey) ? searchKey : AccessibilitySearchKey::AnyType;
694 }
695
696 AccessibilitySearchCriteria accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(const NSDictionary *parameterizedAttribute)
697 {
698     NSString *directionParameter = [parameterizedAttribute objectForKey:@"AXDirection"];
699     NSNumber *immediateDescendantsOnlyParameter = [parameterizedAttribute objectForKey:NSAccessibilityImmediateDescendantsOnly];
700     NSNumber *resultsLimitParameter = [parameterizedAttribute objectForKey:@"AXResultsLimit"];
701     NSString *searchTextParameter = [parameterizedAttribute objectForKey:@"AXSearchText"];
702     WebAccessibilityObjectWrapperBase *startElementParameter = [parameterizedAttribute objectForKey:@"AXStartElement"];
703     NSNumber *visibleOnlyParameter = [parameterizedAttribute objectForKey:@"AXVisibleOnly"];
704     id searchKeyParameter = [parameterizedAttribute objectForKey:@"AXSearchKey"];
705     
706     AccessibilitySearchDirection direction = AccessibilitySearchDirection::Next;
707     if ([directionParameter isKindOfClass:[NSString class]])
708         direction = [directionParameter isEqualToString:@"AXDirectionNext"] ? AccessibilitySearchDirection::Next : AccessibilitySearchDirection::Previous;
709     
710     bool immediateDescendantsOnly = false;
711     if ([immediateDescendantsOnlyParameter isKindOfClass:[NSNumber class]])
712         immediateDescendantsOnly = [immediateDescendantsOnlyParameter boolValue];
713     
714     unsigned resultsLimit = 0;
715     if ([resultsLimitParameter isKindOfClass:[NSNumber class]])
716         resultsLimit = [resultsLimitParameter unsignedIntValue];
717     
718     String searchText;
719     if ([searchTextParameter isKindOfClass:[NSString class]])
720         searchText = searchTextParameter;
721     
722     AXCoreObject* startElement = nullptr;
723     if ([startElementParameter isKindOfClass:[WebAccessibilityObjectWrapperBase class]])
724         startElement = [startElementParameter axBackingObject];
725
726     bool visibleOnly = false;
727     if ([visibleOnlyParameter isKindOfClass:[NSNumber class]])
728         visibleOnly = [visibleOnlyParameter boolValue];
729     
730     AccessibilitySearchCriteria criteria = AccessibilitySearchCriteria(startElement, direction, searchText, resultsLimit, visibleOnly, immediateDescendantsOnly);
731     
732     if ([searchKeyParameter isKindOfClass:[NSString class]])
733         criteria.searchKeys.append(accessibilitySearchKeyForString(searchKeyParameter));
734     else if ([searchKeyParameter isKindOfClass:[NSArray class]]) {
735         size_t searchKeyCount = static_cast<size_t>([searchKeyParameter count]);
736         criteria.searchKeys.reserveInitialCapacity(searchKeyCount);
737         for (size_t i = 0; i < searchKeyCount; ++i) {
738             NSString *searchKey = [searchKeyParameter objectAtIndex:i];
739             if ([searchKey isKindOfClass:[NSString class]])
740                 criteria.searchKeys.uncheckedAppend(accessibilitySearchKeyForString(searchKey));
741         }
742     }
743     
744     return criteria;
745 }
746
747 @end
748
749 #endif // ENABLE(ACCESSIBILITY)