44d3d69bec0c933fce46d8eb9062eff512297075
[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 HAVE(ACCESSIBILITY)
33
34 #import "AXIsolatedTree.h"
35 #import "AXIsolatedTreeNode.h"
36 #import "AXObjectCache.h"
37 #import "AccessibilityARIAGridRow.h"
38 #import "AccessibilityList.h"
39 #import "AccessibilityListBox.h"
40 #import "AccessibilityObjectInterface.h"
41 #import "AccessibilityRenderObject.h"
42 #import "AccessibilityScrollView.h"
43 #import "AccessibilitySpinButton.h"
44 #import "AccessibilityTable.h"
45 #import "AccessibilityTableCell.h"
46 #import "AccessibilityTableColumn.h"
47 #import "AccessibilityTableRow.h"
48 #import "Chrome.h"
49 #import "ChromeClient.h"
50 #import "ColorMac.h"
51 #import "ContextMenuController.h"
52 #import "Editing.h"
53 #import "Font.h"
54 #import "FontCascade.h"
55 #import "Frame.h"
56 #import "FrameLoaderClient.h"
57 #import "FrameSelection.h"
58 #import "HTMLNames.h"
59 #import "LayoutRect.h"
60 #import "LocalizedStrings.h"
61 #import "Page.h"
62 #import "RenderTextControl.h"
63 #import "RenderView.h"
64 #import "RenderWidget.h"
65 #import "ScrollView.h"
66 #import "TextCheckerClient.h"
67 #import "TextCheckingHelper.h"
68 #import "VisibleUnits.h"
69 #import "WAKView.h"
70 #import "WAKWindow.h"
71 #import "WebCoreFrameView.h"
72
73 using namespace WebCore;
74 using namespace HTMLNames;
75
76 // Search Keys
77 #ifndef NSAccessibilityAnyTypeSearchKey
78 #define NSAccessibilityAnyTypeSearchKey @"AXAnyTypeSearchKey"
79 #endif
80
81 #ifndef NSAccessibilityArticleSearchKey
82 #define NSAccessibilityArticleSearchKey @"AXArticleSearchKey"
83 #endif
84
85 #ifndef NSAccessibilityBlockquoteSameLevelSearchKey
86 #define NSAccessibilityBlockquoteSameLevelSearchKey @"AXBlockquoteSameLevelSearchKey"
87 #endif
88
89 #ifndef NSAccessibilityBlockquoteSearchKey
90 #define NSAccessibilityBlockquoteSearchKey @"AXBlockquoteSearchKey"
91 #endif
92
93 #ifndef NSAccessibilityBoldFontSearchKey
94 #define NSAccessibilityBoldFontSearchKey @"AXBoldFontSearchKey"
95 #endif
96
97 #ifndef NSAccessibilityButtonSearchKey
98 #define NSAccessibilityButtonSearchKey @"AXButtonSearchKey"
99 #endif
100
101 #ifndef NSAccessibilityCheckBoxSearchKey
102 #define NSAccessibilityCheckBoxSearchKey @"AXCheckBoxSearchKey"
103 #endif
104
105 #ifndef NSAccessibilityControlSearchKey
106 #define NSAccessibilityControlSearchKey @"AXControlSearchKey"
107 #endif
108
109 #ifndef NSAccessibilityDifferentTypeSearchKey
110 #define NSAccessibilityDifferentTypeSearchKey @"AXDifferentTypeSearchKey"
111 #endif
112
113 #ifndef NSAccessibilityFontChangeSearchKey
114 #define NSAccessibilityFontChangeSearchKey @"AXFontChangeSearchKey"
115 #endif
116
117 #ifndef NSAccessibilityFontColorChangeSearchKey
118 #define NSAccessibilityFontColorChangeSearchKey @"AXFontColorChangeSearchKey"
119 #endif
120
121 #ifndef NSAccessibilityFrameSearchKey
122 #define NSAccessibilityFrameSearchKey @"AXFrameSearchKey"
123 #endif
124
125 #ifndef NSAccessibilityGraphicSearchKey
126 #define NSAccessibilityGraphicSearchKey @"AXGraphicSearchKey"
127 #endif
128
129 #ifndef NSAccessibilityHeadingLevel1SearchKey
130 #define NSAccessibilityHeadingLevel1SearchKey @"AXHeadingLevel1SearchKey"
131 #endif
132
133 #ifndef NSAccessibilityHeadingLevel2SearchKey
134 #define NSAccessibilityHeadingLevel2SearchKey @"AXHeadingLevel2SearchKey"
135 #endif
136
137 #ifndef NSAccessibilityHeadingLevel3SearchKey
138 #define NSAccessibilityHeadingLevel3SearchKey @"AXHeadingLevel3SearchKey"
139 #endif
140
141 #ifndef NSAccessibilityHeadingLevel4SearchKey
142 #define NSAccessibilityHeadingLevel4SearchKey @"AXHeadingLevel4SearchKey"
143 #endif
144
145 #ifndef NSAccessibilityHeadingLevel5SearchKey
146 #define NSAccessibilityHeadingLevel5SearchKey @"AXHeadingLevel5SearchKey"
147 #endif
148
149 #ifndef NSAccessibilityHeadingLevel6SearchKey
150 #define NSAccessibilityHeadingLevel6SearchKey @"AXHeadingLevel6SearchKey"
151 #endif
152
153 #ifndef NSAccessibilityHeadingSameLevelSearchKey
154 #define NSAccessibilityHeadingSameLevelSearchKey @"AXHeadingSameLevelSearchKey"
155 #endif
156
157 #ifndef NSAccessibilityHeadingSearchKey
158 #define NSAccessibilityHeadingSearchKey @"AXHeadingSearchKey"
159 #endif
160
161 #ifndef NSAccessibilityHighlightedSearchKey
162 #define NSAccessibilityHighlightedSearchKey @"AXHighlightedSearchKey"
163 #endif
164
165 #ifndef NSAccessibilityItalicFontSearchKey
166 #define NSAccessibilityItalicFontSearchKey @"AXItalicFontSearchKey"
167 #endif
168
169 #ifndef NSAccessibilityLandmarkSearchKey
170 #define NSAccessibilityLandmarkSearchKey @"AXLandmarkSearchKey"
171 #endif
172
173 #ifndef NSAccessibilityLinkSearchKey
174 #define NSAccessibilityLinkSearchKey @"AXLinkSearchKey"
175 #endif
176
177 #ifndef NSAccessibilityListSearchKey
178 #define NSAccessibilityListSearchKey @"AXListSearchKey"
179 #endif
180
181 #ifndef NSAccessibilityLiveRegionSearchKey
182 #define NSAccessibilityLiveRegionSearchKey @"AXLiveRegionSearchKey"
183 #endif
184
185 #ifndef NSAccessibilityMisspelledWordSearchKey
186 #define NSAccessibilityMisspelledWordSearchKey @"AXMisspelledWordSearchKey"
187 #endif
188
189 #ifndef NSAccessibilityOutlineSearchKey
190 #define NSAccessibilityOutlineSearchKey @"AXOutlineSearchKey"
191 #endif
192
193 #ifndef NSAccessibilityPlainTextSearchKey
194 #define NSAccessibilityPlainTextSearchKey @"AXPlainTextSearchKey"
195 #endif
196
197 #ifndef NSAccessibilityRadioGroupSearchKey
198 #define NSAccessibilityRadioGroupSearchKey @"AXRadioGroupSearchKey"
199 #endif
200
201 #ifndef NSAccessibilitySameTypeSearchKey
202 #define NSAccessibilitySameTypeSearchKey @"AXSameTypeSearchKey"
203 #endif
204
205 #ifndef NSAccessibilityStaticTextSearchKey
206 #define NSAccessibilityStaticTextSearchKey @"AXStaticTextSearchKey"
207 #endif
208
209 #ifndef NSAccessibilityStyleChangeSearchKey
210 #define NSAccessibilityStyleChangeSearchKey @"AXStyleChangeSearchKey"
211 #endif
212
213 #ifndef NSAccessibilityTableSameLevelSearchKey
214 #define NSAccessibilityTableSameLevelSearchKey @"AXTableSameLevelSearchKey"
215 #endif
216
217 #ifndef NSAccessibilityTableSearchKey
218 #define NSAccessibilityTableSearchKey @"AXTableSearchKey"
219 #endif
220
221 #ifndef NSAccessibilityTextFieldSearchKey
222 #define NSAccessibilityTextFieldSearchKey @"AXTextFieldSearchKey"
223 #endif
224
225 #ifndef NSAccessibilityUnderlineSearchKey
226 #define NSAccessibilityUnderlineSearchKey @"AXUnderlineSearchKey"
227 #endif
228
229 #ifndef NSAccessibilityUnvisitedLinkSearchKey
230 #define NSAccessibilityUnvisitedLinkSearchKey @"AXUnvisitedLinkSearchKey"
231 #endif
232
233 #ifndef NSAccessibilityVisitedLinkSearchKey
234 #define NSAccessibilityVisitedLinkSearchKey @"AXVisitedLinkSearchKey"
235 #endif
236
237 // Search
238 #ifndef NSAccessibilityImmediateDescendantsOnly
239 #define NSAccessibilityImmediateDescendantsOnly @"AXImmediateDescendantsOnly"
240 #endif
241
242 static NSArray *convertMathPairsToNSArray(const AccessibilityObject::AccessibilityMathMultiscriptPairs& pairs, NSString *subscriptKey, NSString *superscriptKey)
243 {
244     NSMutableArray *array = [NSMutableArray arrayWithCapacity:pairs.size()];
245     for (const auto& pair : pairs) {
246         NSMutableDictionary *pairDictionary = [NSMutableDictionary dictionary];
247         if (pair.first && pair.first->wrapper() && !pair.first->accessibilityIsIgnored())
248             [pairDictionary setObject:pair.first->wrapper() forKey:subscriptKey];
249         if (pair.second && pair.second->wrapper() && !pair.second->accessibilityIsIgnored())
250             [pairDictionary setObject:pair.second->wrapper() forKey:superscriptKey];
251         [array addObject:pairDictionary];
252     }
253     return array;
254 }
255
256 NSArray *convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
257 {
258     NSMutableArray *array = [NSMutableArray arrayWithCapacity:vector.size()];
259     for (const auto& child : vector) {
260         auto wrapper = (WebAccessibilityObjectWrapperBase *)child->wrapper();
261         ASSERT(wrapper);
262         if (wrapper) {
263             // We want to return the attachment view instead of the object representing the attachment,
264             // otherwise, we get palindrome errors in the AX hierarchy.
265             if (child->isAttachment() && [wrapper attachmentView])
266                 [array addObject:[wrapper attachmentView]];
267             else
268                 [array addObject:wrapper];
269         }
270     }
271     return [[array copy] autorelease];
272 }
273
274 @implementation WebAccessibilityObjectWrapperBase
275
276 @synthesize identifier=_identifier;
277 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
278 @synthesize isolatedTreeIdentifier=_isolatedTreeIdentifier;
279 #endif
280
281 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
282 {
283     if (!(self = [super init]))
284         return nil;
285
286     m_object = axObject;
287     _identifier = m_object->axObjectID();
288
289     return self;
290 }
291
292 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
293 - (RefPtr<WebCore::AXIsolatedTreeNode>)isolatedTreeNode
294 {
295     RELEASE_ASSERT(!isMainThread());
296     return AXIsolatedTree::treeForID(_isolatedTreeIdentifier)->nodeForID(_identifier);
297 }
298 #endif
299
300 - (void)detach
301 {
302     m_object = nullptr;
303     _identifier = 0;
304
305 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
306     _isolatedTreeIdentifier = 0;
307 #endif
308 }
309
310 - (BOOL)updateObjectBackingStore
311 {
312 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
313     RELEASE_ASSERT(!isMainThread());
314     AXIsolatedTree::treeForID(self.isolatedTreeIdentifier)->applyPendingChanges();
315     return _identifier;
316 #else
317     // Calling updateBackingStore() can invalidate this element so self must be retained.
318     // If it does become invalidated, m_object will be nil.
319     CFRetain((__bridge CFTypeRef)self);
320     CFAutorelease((__bridge CFTypeRef)self);
321
322     if (!m_object)
323         return NO;
324     
325     m_object->updateBackingStore();
326     if (!m_object)
327         return NO;
328     
329     return YES;
330 #endif
331 }
332
333 - (id)attachmentView
334 {
335     return nil;
336 }
337
338 - (AccessibilityObject*)accessibilityObject
339 {
340     return m_object;
341 }
342
343 // FIXME: Different kinds of elements are putting the title tag to use in different
344 // AX fields. This should be rectified, but in the initial patch I want to achieve
345 // parity with existing behavior.
346 - (BOOL)titleTagShouldBeUsedInDescriptionField
347 {
348     return (m_object->isLink() && !m_object->isImageMapLink()) || m_object->isImage();
349 }
350
351 // On iOS, we don't have to return the value in the title. We can return the actual title, given the API.
352 - (BOOL)fileUploadButtonReturnsValueInTitle
353 {
354     return YES;
355 }
356
357 // This should be the "visible" text that's actually on the screen if possible.
358 // If there's alternative text, that can override the title.
359 - (NSString *)baseAccessibilityTitle
360 {
361     // Static text objects should not have a title. Its content is communicated in its AXValue.
362     if (m_object->roleValue() == AccessibilityRole::StaticText)
363         return [NSString string];
364
365     // A file upload button presents a challenge because it has button text and a value, but the
366     // API doesn't support this paradigm.
367     // The compromise is to return the button type in the role description and the value of the file path in the title
368     if (m_object->isFileUploadButton() && [self fileUploadButtonReturnsValueInTitle])
369         return m_object->stringValue();
370     
371     Vector<AccessibilityText> textOrder;
372     m_object->accessibilityText(textOrder);
373     
374     for (const auto& text : textOrder) {
375         // If we have alternative text, then we should not expose a title.
376         if (text.textSource == AccessibilityTextSource::Alternative)
377             break;
378         
379         // Once we encounter visible text, or the text from our children that should be used foremost.
380         if (text.textSource == AccessibilityTextSource::Visible || text.textSource == AccessibilityTextSource::Children)
381             return text.text;
382         
383         // If there's an element that labels this object and it's not exposed, then we should use
384         // that text as our title.
385         if (text.textSource == AccessibilityTextSource::LabelByElement && !m_object->exposesTitleUIElement())
386             return text.text;
387     }
388     
389     return [NSString string];
390 }
391
392 #define _axBackingObject self.axBackingObject
393 - (WebCore::AccessibilityObjectInterface*)axBackingObject
394 {
395 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
396     return self.isolatedTreeNode.get();
397 #else
398     return m_object;
399 #endif
400 }
401
402 - (NSString *)baseAccessibilityDescription
403 {
404     // Static text objects should not have a description. Its content is communicated in its AXValue.
405     // One exception is the media control labels that have a value and a description. Those are set programatically.
406     if (_axBackingObject->roleValue() == AccessibilityRole::StaticText && !_axBackingObject->isMediaControlLabel())
407         return [NSString string];
408     
409     Vector<AccessibilityText> textOrder;
410     m_object->accessibilityText(textOrder);
411
412     NSMutableString *returnText = [NSMutableString string];
413     bool visibleTextAvailable = false;
414     for (const auto& text : textOrder) {
415         if (text.textSource == AccessibilityTextSource::Alternative) {
416             [returnText appendString:text.text];
417             break;
418         }
419         
420         switch (text.textSource) {
421         // These are sub-components of one element (Attachment) that are re-combined in OSX and iOS.
422         case AccessibilityTextSource::Title:
423         case AccessibilityTextSource::Subtitle:
424         case AccessibilityTextSource::Action: {
425             if (!text.text.length())
426                 break;
427             if ([returnText length])
428                 [returnText appendString:@", "];
429             [returnText appendString:text.text];
430             break;
431         }
432         case AccessibilityTextSource::Visible:
433         case AccessibilityTextSource::Children:
434         case AccessibilityTextSource::LabelByElement:
435             visibleTextAvailable = true;
436             break;
437         default:
438             break;
439         }
440         
441         if (text.textSource == AccessibilityTextSource::TitleTag && !visibleTextAvailable) {
442             [returnText appendString:text.text];
443             break;
444         }
445     }
446     
447     return returnText;
448 }
449
450 - (NSArray<NSString *> *)baseAccessibilitySpeechHint
451 {
452     auto speak = m_object->speakAsProperty();
453     NSMutableArray<NSString *> *hints = [NSMutableArray array];
454     if (speak & SpeakAs::SpellOut)
455         [hints addObject:@"spell-out"];
456     else
457         [hints addObject:@"normal"];
458
459     if (speak & SpeakAs::Digits)
460         [hints addObject:@"digits"];
461     if (speak & SpeakAs::LiteralPunctuation)
462         [hints addObject:@"literal-punctuation"];
463     if (speak & SpeakAs::NoPunctuation)
464         [hints addObject:@"no-punctuation"];
465     
466     return hints;
467 }
468
469 - (NSString *)baseAccessibilityHelpText
470 {
471     Vector<AccessibilityText> textOrder;
472     m_object->accessibilityText(textOrder);
473     
474     bool descriptiveTextAvailable = false;
475     for (const auto& text : textOrder) {
476         if (text.textSource == AccessibilityTextSource::Help || text.textSource == AccessibilityTextSource::Summary)
477             return text.text;
478         
479         // If an element does NOT have other descriptive text the title tag should be used as its descriptive text.
480         // But, if those ARE available, then the title tag should be used for help text instead.
481         switch (text.textSource) {
482         case AccessibilityTextSource::Alternative:
483         case AccessibilityTextSource::Visible:
484         case AccessibilityTextSource::Children:
485         case AccessibilityTextSource::LabelByElement:
486             descriptiveTextAvailable = true;
487             break;
488         default:
489             break;
490         }
491         
492         if (text.textSource == AccessibilityTextSource::TitleTag && descriptiveTextAvailable)
493             return text.text;
494     }
495     
496     return [NSString string];
497 }
498
499 struct PathConversionInfo {
500     WebAccessibilityObjectWrapperBase *wrapper;
501     CGMutablePathRef path;
502 };
503
504 static void convertPathToScreenSpaceFunction(PathConversionInfo& conversion, const PathElement& element)
505 {
506     WebAccessibilityObjectWrapperBase *wrapper = conversion.wrapper;
507     CGMutablePathRef newPath = conversion.path;
508     FloatRect rect;
509     switch (element.type) {
510     case PathElementMoveToPoint:
511     {
512         rect = FloatRect(element.points[0], FloatSize());
513         CGPoint newPoint = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
514         CGPathMoveToPoint(newPath, nil, newPoint.x, newPoint.y);
515         break;
516     }
517     case PathElementAddLineToPoint:
518     {
519         rect = FloatRect(element.points[0], FloatSize());
520         CGPoint newPoint = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
521         CGPathAddLineToPoint(newPath, nil, newPoint.x, newPoint.y);
522         break;
523     }
524     case PathElementAddQuadCurveToPoint:
525     {
526         rect = FloatRect(element.points[0], FloatSize());
527         CGPoint newPoint1 = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
528
529         rect = FloatRect(element.points[1], FloatSize());
530         CGPoint newPoint2 = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
531         CGPathAddQuadCurveToPoint(newPath, nil, newPoint1.x, newPoint1.y, newPoint2.x, newPoint2.y);
532         break;
533     }
534     case PathElementAddCurveToPoint:
535     {
536         rect = FloatRect(element.points[0], FloatSize());
537         CGPoint newPoint1 = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
538
539         rect = FloatRect(element.points[1], FloatSize());
540         CGPoint newPoint2 = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
541
542         rect = FloatRect(element.points[2], FloatSize());
543         CGPoint newPoint3 = [wrapper convertRectToSpace:rect space:ScreenSpace].origin;
544         CGPathAddCurveToPoint(newPath, nil, newPoint1.x, newPoint1.y, newPoint2.x, newPoint2.y, newPoint3.x, newPoint3.y);
545         break;
546     }
547     case PathElementCloseSubpath:
548     {
549         CGPathCloseSubpath(newPath);
550         break;
551     }
552     }
553 }
554
555 - (CGPathRef)convertPathToScreenSpace:(Path &)path
556 {
557     PathConversionInfo conversion = { self, CGPathCreateMutable() };
558     path.apply([&conversion](const PathElement& pathElement) {
559         convertPathToScreenSpaceFunction(conversion, pathElement);
560     });
561     CFAutorelease(conversion.path);
562     return conversion.path;
563 }
564
565 - (id)_accessibilityWebDocumentView
566 {
567     ASSERT_NOT_REACHED();
568     // Overridden by sub-classes
569     return nil;
570 }
571
572 - (CGRect)convertRectToSpace:(WebCore::FloatRect &)rect space:(ConversionSpace)space
573 {
574     if (!m_object)
575         return CGRectZero;
576     
577     CGSize size = CGSizeMake(rect.size().width(), rect.size().height());
578     CGPoint point = CGPointMake(rect.x(), rect.y());
579     
580     CGRect cgRect = CGRectMake(point.x, point.y, size.width, size.height);
581
582     // WebKit1 code path... platformWidget() exists.
583     FrameView* frameView = m_object->documentFrameView();
584 #if PLATFORM(IOS_FAMILY)
585     WAKView* documentView = frameView ? frameView->documentView() : nullptr;
586     if (documentView) {
587         cgRect = [documentView convertRect:cgRect toView:nil];
588         
589         // we need the web document view to give us our final screen coordinates
590         // because that can take account of the scroller
591         id webDocument = [self _accessibilityWebDocumentView];
592         if (webDocument)
593             cgRect = [webDocument convertRect:cgRect toView:nil];
594     }
595 #else
596     if (frameView && frameView->platformWidget()) {
597         NSRect nsRect = NSRectFromCGRect(cgRect);
598         NSView* view = frameView->documentView();
599         ALLOW_DEPRECATED_DECLARATIONS_BEGIN
600         nsRect = [[view window] convertRectToScreen:[view convertRect:nsRect toView:nil]];
601         ALLOW_DEPRECATED_DECLARATIONS_END
602         cgRect = NSRectToCGRect(nsRect);
603     }
604 #endif
605     else {
606         // Find the appropriate scroll view to use to convert the contents to the window.
607         ScrollView* scrollView = nullptr;
608         const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, [] (const AccessibilityObject& object) {
609             return is<AccessibilityScrollView>(object);
610         });
611         if (parent)
612             scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
613         
614         auto intRect = snappedIntRect(IntRect(cgRect));
615         if (scrollView)
616             intRect = scrollView->contentsToRootView(intRect);
617         
618         if (space == ScreenSpace) {
619             auto page = m_object->page();
620             
621             // If we have an empty chrome client (like SVG) then we should use the page
622             // of the scroll view parent to help us get to the screen rect.
623             if (parent && page && page->chrome().client().isEmptyChromeClient())
624                 page = parent->page();
625             
626             if (page) {
627 #if PLATFORM(IOS_FAMILY)
628                 intRect = page->chrome().rootViewToAccessibilityScreen(intRect);
629 #else
630                 intRect = page->chrome().rootViewToScreen(intRect);
631 #endif
632             }
633         }
634         
635         cgRect = (CGRect)intRect;
636     }
637     
638     return cgRect;
639 }
640
641 - (NSString *)ariaLandmarkRoleDescription
642 {
643     switch (m_object->roleValue()) {
644     case AccessibilityRole::LandmarkBanner:
645         return AXARIAContentGroupText(@"ARIALandmarkBanner");
646     case AccessibilityRole::LandmarkComplementary:
647         return AXARIAContentGroupText(@"ARIALandmarkComplementary");
648     case AccessibilityRole::LandmarkContentInfo:
649         return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
650     case AccessibilityRole::LandmarkMain:
651         return AXARIAContentGroupText(@"ARIALandmarkMain");
652     case AccessibilityRole::LandmarkNavigation:
653         return AXARIAContentGroupText(@"ARIALandmarkNavigation");
654     case AccessibilityRole::LandmarkDocRegion:
655     case AccessibilityRole::LandmarkRegion:
656         return AXARIAContentGroupText(@"ARIALandmarkRegion");
657     case AccessibilityRole::LandmarkSearch:
658         return AXARIAContentGroupText(@"ARIALandmarkSearch");
659     case AccessibilityRole::ApplicationAlert:
660         return AXARIAContentGroupText(@"ARIAApplicationAlert");
661     case AccessibilityRole::ApplicationAlertDialog:
662         return AXARIAContentGroupText(@"ARIAApplicationAlertDialog");
663     case AccessibilityRole::ApplicationDialog:
664         return AXARIAContentGroupText(@"ARIAApplicationDialog");
665     case AccessibilityRole::ApplicationLog:
666         return AXARIAContentGroupText(@"ARIAApplicationLog");
667     case AccessibilityRole::ApplicationMarquee:
668         return AXARIAContentGroupText(@"ARIAApplicationMarquee");
669     case AccessibilityRole::ApplicationStatus:
670         return AXARIAContentGroupText(@"ARIAApplicationStatus");
671     case AccessibilityRole::ApplicationTimer:
672         return AXARIAContentGroupText(@"ARIAApplicationTimer");
673     case AccessibilityRole::Document:
674         return AXARIAContentGroupText(@"ARIADocument");
675     case AccessibilityRole::DocumentArticle:
676         return AXARIAContentGroupText(@"ARIADocumentArticle");
677     case AccessibilityRole::DocumentMath:
678         return AXARIAContentGroupText(@"ARIADocumentMath");
679     case AccessibilityRole::DocumentNote:
680         return AXARIAContentGroupText(@"ARIADocumentNote");
681     case AccessibilityRole::UserInterfaceTooltip:
682         return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
683     case AccessibilityRole::TabPanel:
684         return AXARIAContentGroupText(@"ARIATabPanel");
685     case AccessibilityRole::WebApplication:
686         return AXARIAContentGroupText(@"ARIAWebApplication");
687     default:
688         return nil;
689     }
690 }
691
692 - (NSString *)accessibilityPlatformMathSubscriptKey
693 {
694     ASSERT_NOT_REACHED();
695     return nil;
696 }
697
698 - (NSString *)accessibilityPlatformMathSuperscriptKey
699 {
700     ASSERT_NOT_REACHED();
701     return nil;    
702 }
703
704 - (NSArray *)accessibilityMathPostscriptPairs
705 {
706     AccessibilityObject::AccessibilityMathMultiscriptPairs pairs;
707     m_object->mathPostscripts(pairs);
708     return convertMathPairsToNSArray(pairs, [self accessibilityPlatformMathSubscriptKey], [self accessibilityPlatformMathSuperscriptKey]);
709 }
710
711 - (NSArray *)accessibilityMathPrescriptPairs
712 {
713     AccessibilityObject::AccessibilityMathMultiscriptPairs pairs;
714     m_object->mathPrescripts(pairs);
715     return convertMathPairsToNSArray(pairs, [self accessibilityPlatformMathSubscriptKey], [self accessibilityPlatformMathSuperscriptKey]);
716 }
717
718 // This is set by DRT when it wants to listen for notifications.
719 static BOOL accessibilityShouldRepostNotifications;
720 + (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
721 {
722     accessibilityShouldRepostNotifications = repost;
723 #if PLATFORM(MAC)
724     AXObjectCache::setShouldRepostNotificationsForTests(repost);
725 #endif
726 }
727
728 - (void)accessibilityPostedNotification:(NSString *)notificationName
729 {
730     if (accessibilityShouldRepostNotifications)
731         [self accessibilityPostedNotification:notificationName userInfo:nil];
732 }
733
734 static bool isValueTypeSupported(id value)
735 {
736     return [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[WebAccessibilityObjectWrapperBase class]];
737 }
738
739 static NSArray *arrayRemovingNonSupportedTypes(NSArray *array)
740 {
741     ASSERT([array isKindOfClass:[NSArray class]]);
742     NSMutableArray *mutableArray = [array mutableCopy];
743     for (NSUInteger i = 0; i < [mutableArray count];) {
744         id value = [mutableArray objectAtIndex:i];
745         if ([value isKindOfClass:[NSDictionary class]])
746             [mutableArray replaceObjectAtIndex:i withObject:dictionaryRemovingNonSupportedTypes(value)];
747         else if ([value isKindOfClass:[NSArray class]])
748             [mutableArray replaceObjectAtIndex:i withObject:arrayRemovingNonSupportedTypes(value)];
749         else if (!isValueTypeSupported(value)) {
750             [mutableArray removeObjectAtIndex:i];
751             continue;
752         }
753         i++;
754     }
755     return [mutableArray autorelease];
756 }
757
758 static NSDictionary *dictionaryRemovingNonSupportedTypes(NSDictionary *dictionary)
759 {
760     if (!dictionary)
761         return nil;
762     ASSERT([dictionary isKindOfClass:[NSDictionary class]]);
763     NSMutableDictionary *mutableDictionary = [dictionary mutableCopy];
764     for (NSString *key in dictionary) {
765         id value = [dictionary objectForKey:key];
766         if ([value isKindOfClass:[NSDictionary class]])
767             [mutableDictionary setObject:dictionaryRemovingNonSupportedTypes(value) forKey:key];
768         else if ([value isKindOfClass:[NSArray class]])
769             [mutableDictionary setObject:arrayRemovingNonSupportedTypes(value) forKey:key];
770         else if (!isValueTypeSupported(value))
771             [mutableDictionary removeObjectForKey:key];
772     }
773     return [mutableDictionary autorelease];
774 }
775
776 - (void)accessibilityPostedNotification:(NSString *)notificationName userInfo:(NSDictionary *)userInfo
777 {
778     if (accessibilityShouldRepostNotifications) {
779         ASSERT(notificationName);
780         userInfo = dictionaryRemovingNonSupportedTypes(userInfo);
781         NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", userInfo, @"userInfo", nil];
782         [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:self userInfo:info];
783     }
784 }
785
786 #pragma mark Search helpers
787
788 typedef HashMap<String, AccessibilitySearchKey> AccessibilitySearchKeyMap;
789
790 struct SearchKeyEntry {
791     String key;
792     AccessibilitySearchKey value;
793 };
794
795 static AccessibilitySearchKeyMap* createAccessibilitySearchKeyMap()
796 {
797     const SearchKeyEntry searchKeys[] = {
798         { NSAccessibilityAnyTypeSearchKey, AccessibilitySearchKey::AnyType },
799         { NSAccessibilityArticleSearchKey, AccessibilitySearchKey::Article },
800         { NSAccessibilityBlockquoteSameLevelSearchKey, AccessibilitySearchKey::BlockquoteSameLevel },
801         { NSAccessibilityBlockquoteSearchKey, AccessibilitySearchKey::Blockquote },
802         { NSAccessibilityBoldFontSearchKey, AccessibilitySearchKey::BoldFont },
803         { NSAccessibilityButtonSearchKey, AccessibilitySearchKey::Button },
804         { NSAccessibilityCheckBoxSearchKey, AccessibilitySearchKey::CheckBox },
805         { NSAccessibilityControlSearchKey, AccessibilitySearchKey::Control },
806         { NSAccessibilityDifferentTypeSearchKey, AccessibilitySearchKey::DifferentType },
807         { NSAccessibilityFontChangeSearchKey, AccessibilitySearchKey::FontChange },
808         { NSAccessibilityFontColorChangeSearchKey, AccessibilitySearchKey::FontColorChange },
809         { NSAccessibilityFrameSearchKey, AccessibilitySearchKey::Frame },
810         { NSAccessibilityGraphicSearchKey, AccessibilitySearchKey::Graphic },
811         { NSAccessibilityHeadingLevel1SearchKey, AccessibilitySearchKey::HeadingLevel1 },
812         { NSAccessibilityHeadingLevel2SearchKey, AccessibilitySearchKey::HeadingLevel2 },
813         { NSAccessibilityHeadingLevel3SearchKey, AccessibilitySearchKey::HeadingLevel3 },
814         { NSAccessibilityHeadingLevel4SearchKey, AccessibilitySearchKey::HeadingLevel4 },
815         { NSAccessibilityHeadingLevel5SearchKey, AccessibilitySearchKey::HeadingLevel5 },
816         { NSAccessibilityHeadingLevel6SearchKey, AccessibilitySearchKey::HeadingLevel6 },
817         { NSAccessibilityHeadingSameLevelSearchKey, AccessibilitySearchKey::HeadingSameLevel },
818         { NSAccessibilityHeadingSearchKey, AccessibilitySearchKey::Heading },
819         { NSAccessibilityHighlightedSearchKey, AccessibilitySearchKey::Highlighted },
820         { NSAccessibilityItalicFontSearchKey, AccessibilitySearchKey::ItalicFont },
821         { NSAccessibilityLandmarkSearchKey, AccessibilitySearchKey::Landmark },
822         { NSAccessibilityLinkSearchKey, AccessibilitySearchKey::Link },
823         { NSAccessibilityListSearchKey, AccessibilitySearchKey::List },
824         { NSAccessibilityLiveRegionSearchKey, AccessibilitySearchKey::LiveRegion },
825         { NSAccessibilityMisspelledWordSearchKey, AccessibilitySearchKey::MisspelledWord },
826         { NSAccessibilityOutlineSearchKey, AccessibilitySearchKey::Outline },
827         { NSAccessibilityPlainTextSearchKey, AccessibilitySearchKey::PlainText },
828         { NSAccessibilityRadioGroupSearchKey, AccessibilitySearchKey::RadioGroup },
829         { NSAccessibilitySameTypeSearchKey, AccessibilitySearchKey::SameType },
830         { NSAccessibilityStaticTextSearchKey, AccessibilitySearchKey::StaticText },
831         { NSAccessibilityStyleChangeSearchKey, AccessibilitySearchKey::StyleChange },
832         { NSAccessibilityTableSameLevelSearchKey, AccessibilitySearchKey::TableSameLevel },
833         { NSAccessibilityTableSearchKey, AccessibilitySearchKey::Table },
834         { NSAccessibilityTextFieldSearchKey, AccessibilitySearchKey::TextField },
835         { NSAccessibilityUnderlineSearchKey, AccessibilitySearchKey::Underline },
836         { NSAccessibilityUnvisitedLinkSearchKey, AccessibilitySearchKey::UnvisitedLink },
837         { NSAccessibilityVisitedLinkSearchKey, AccessibilitySearchKey::VisitedLink }
838     };
839     
840     AccessibilitySearchKeyMap* searchKeyMap = new AccessibilitySearchKeyMap;
841     for (size_t i = 0; i < WTF_ARRAY_LENGTH(searchKeys); i++)
842         searchKeyMap->set(searchKeys[i].key, searchKeys[i].value);
843     
844     return searchKeyMap;
845 }
846
847 static AccessibilitySearchKey accessibilitySearchKeyForString(const String& value)
848 {
849     if (value.isEmpty())
850         return AccessibilitySearchKey::AnyType;
851     
852     static const AccessibilitySearchKeyMap* searchKeyMap = createAccessibilitySearchKeyMap();
853     AccessibilitySearchKey searchKey = searchKeyMap->get(value);    
854     return static_cast<int>(searchKey) ? searchKey : AccessibilitySearchKey::AnyType;
855 }
856
857 AccessibilitySearchCriteria accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(const NSDictionary *parameterizedAttribute)
858 {
859     NSString *directionParameter = [parameterizedAttribute objectForKey:@"AXDirection"];
860     NSNumber *immediateDescendantsOnlyParameter = [parameterizedAttribute objectForKey:NSAccessibilityImmediateDescendantsOnly];
861     NSNumber *resultsLimitParameter = [parameterizedAttribute objectForKey:@"AXResultsLimit"];
862     NSString *searchTextParameter = [parameterizedAttribute objectForKey:@"AXSearchText"];
863     WebAccessibilityObjectWrapperBase *startElementParameter = [parameterizedAttribute objectForKey:@"AXStartElement"];
864     NSNumber *visibleOnlyParameter = [parameterizedAttribute objectForKey:@"AXVisibleOnly"];
865     id searchKeyParameter = [parameterizedAttribute objectForKey:@"AXSearchKey"];
866     
867     AccessibilitySearchDirection direction = AccessibilitySearchDirection::Next;
868     if ([directionParameter isKindOfClass:[NSString class]])
869         direction = [directionParameter isEqualToString:@"AXDirectionNext"] ? AccessibilitySearchDirection::Next : AccessibilitySearchDirection::Previous;
870     
871     bool immediateDescendantsOnly = false;
872     if ([immediateDescendantsOnlyParameter isKindOfClass:[NSNumber class]])
873         immediateDescendantsOnly = [immediateDescendantsOnlyParameter boolValue];
874     
875     unsigned resultsLimit = 0;
876     if ([resultsLimitParameter isKindOfClass:[NSNumber class]])
877         resultsLimit = [resultsLimitParameter unsignedIntValue];
878     
879     String searchText;
880     if ([searchTextParameter isKindOfClass:[NSString class]])
881         searchText = searchTextParameter;
882     
883     AccessibilityObject* startElement = nullptr;
884     if ([startElementParameter isKindOfClass:[WebAccessibilityObjectWrapperBase class]])
885         startElement = [startElementParameter accessibilityObject];
886     
887     bool visibleOnly = false;
888     if ([visibleOnlyParameter isKindOfClass:[NSNumber class]])
889         visibleOnly = [visibleOnlyParameter boolValue];
890     
891     AccessibilitySearchCriteria criteria = AccessibilitySearchCriteria(startElement, direction, searchText, resultsLimit, visibleOnly, immediateDescendantsOnly);
892     
893     if ([searchKeyParameter isKindOfClass:[NSString class]])
894         criteria.searchKeys.append(accessibilitySearchKeyForString(searchKeyParameter));
895     else if ([searchKeyParameter isKindOfClass:[NSArray class]]) {
896         size_t searchKeyCount = static_cast<size_t>([searchKeyParameter count]);
897         criteria.searchKeys.reserveInitialCapacity(searchKeyCount);
898         for (size_t i = 0; i < searchKeyCount; ++i) {
899             NSString *searchKey = [searchKeyParameter objectAtIndex:i];
900             if ([searchKey isKindOfClass:[NSString class]])
901                 criteria.searchKeys.uncheckedAppend(accessibilitySearchKeyForString(searchKey));
902         }
903     }
904     
905     return criteria;
906 }
907
908 @end
909
910 #endif // HAVE(ACCESSIBILITY)