1/* 2 * Copyright (C) 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 * 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. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "WKAccessibilityWebPageObject.h" 28 29#if PLATFORM(MAC) 30 31#import "WebFrame.h" 32#import "WebPage.h" 33#import "WKArray.h" 34#import "WKNumber.h" 35#import "WKRetainPtr.h" 36#import "WKSharedAPICast.h" 37#import "WKString.h" 38#import "WKStringCF.h" 39#import <WebCore/AXObjectCache.h> 40#import <WebCore/FrameView.h> 41#import <WebCore/MainFrame.h> 42#import <WebCore/Page.h> 43#import <WebCore/ScrollView.h> 44#import <WebCore/Scrollbar.h> 45#import <WebKitSystemInterface.h> 46#import <wtf/ObjcRuntimeExtras.h> 47 48using namespace WebCore; 49using namespace WebKit; 50 51@implementation WKAccessibilityWebPageObject 52 53- (id)accessibilityRootObjectWrapper 54{ 55 if (!WebCore::AXObjectCache::accessibilityEnabled()) 56 WebCore::AXObjectCache::enableAccessibility(); 57 58 NSObject* mainFramePluginAccessibilityObjectWrapper = m_page->accessibilityObjectForMainFramePlugin(); 59 if (mainFramePluginAccessibilityObjectWrapper) 60 return mainFramePluginAccessibilityObjectWrapper; 61 62 WebCore::Page* page = m_page->corePage(); 63 if (!page) 64 return nil; 65 66 WebCore::Frame& core = page->mainFrame(); 67 if (!core.document()) 68 return nil; 69 70 AccessibilityObject* root = core.document()->axObjectCache()->rootObject(); 71 if (!root) 72 return nil; 73 74 return root->wrapper(); 75} 76 77- (void)setWebPage:(WebPage*)page 78{ 79 m_page = page; 80} 81 82- (void)setRemoteParent:(id)parent 83{ 84 if (parent != m_parent) { 85 [m_parent release]; 86 m_parent = [parent retain]; 87 } 88} 89 90- (void)dealloc 91{ 92 WKUnregisterUniqueIdForElement(self); 93 [m_accessibilityChildren release]; 94 [m_attributeNames release]; 95 [m_parent release]; 96 [super dealloc]; 97} 98 99- (BOOL)accessibilityIsIgnored 100{ 101 return NO; 102} 103 104- (NSArray *)accessibilityAttributeNames 105{ 106 if (!m_attributeNames) 107 m_attributeNames = [[NSArray alloc] initWithObjects: 108 NSAccessibilityRoleAttribute, NSAccessibilityRoleDescriptionAttribute, NSAccessibilityFocusedAttribute, 109 NSAccessibilityParentAttribute, NSAccessibilityWindowAttribute, NSAccessibilityTopLevelUIElementAttribute, 110 NSAccessibilityPositionAttribute, NSAccessibilitySizeAttribute, NSAccessibilityChildrenAttribute, nil]; 111 112 return m_attributeNames; 113} 114 115- (NSArray *)accessibilityParameterizedAttributeNames 116{ 117 WKRetainPtr<WKArrayRef> result = adoptWK(m_page->pageOverlayCopyAccessibilityAttributesNames(true)); 118 if (!result) 119 return nil; 120 121 NSMutableArray *names = [NSMutableArray array]; 122 size_t count = WKArrayGetSize(result.get()); 123 for (size_t k = 0; k < count; k++) { 124 WKTypeRef item = WKArrayGetItemAtIndex(result.get(), k); 125 if (toImpl(item)->type() == API::String::APIType) { 126 RetainPtr<CFStringRef> name = adoptCF(WKStringCopyCFString(kCFAllocatorDefault, (WKStringRef)item)); 127 [names addObject:(NSString *)name.get()]; 128 } 129 } 130 131 return names; 132} 133 134- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute 135{ 136 return NO; 137} 138 139- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute 140{ 141 return; 142} 143 144- (NSArray *)accessibilityActionNames 145{ 146 return [NSArray array]; 147} 148 149- (NSArray *)accessibilityChildren 150{ 151 id wrapper = [self accessibilityRootObjectWrapper]; 152 if (!wrapper) 153 return [NSArray array]; 154 155 return [NSArray arrayWithObject:wrapper]; 156} 157 158- (id)accessibilityAttributeValue:(NSString *)attribute 159{ 160 if (!WebCore::AXObjectCache::accessibilityEnabled()) 161 WebCore::AXObjectCache::enableAccessibility(); 162 163 if ([attribute isEqualToString:NSAccessibilityParentAttribute]) 164 return m_parent; 165 if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) 166 return [m_parent accessibilityAttributeValue:NSAccessibilityWindowAttribute]; 167 if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) 168 return [m_parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; 169 if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) 170 return NSAccessibilityGroupRole; 171 if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) 172 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil); 173 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) 174 return [NSNumber numberWithBool:NO]; 175 176 if (!m_page) 177 return nil; 178 179 if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { 180 const WebCore::FloatPoint& point = m_page->accessibilityPosition(); 181 return [NSValue valueWithPoint:NSMakePoint(point.x(), point.y())]; 182 } 183 if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) { 184 const IntSize& s = m_page->size(); 185 return [NSValue valueWithSize:NSMakeSize(s.width(), s.height())]; 186 } 187 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) 188 return [self accessibilityChildren]; 189 190 return nil; 191} 192 193- (NSPoint)_convertScreenPointToRootView:(NSPoint)point 194{ 195 return m_page->screenToRootView(IntPoint(point.x, point.y)); 196} 197 198- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter 199{ 200 WKRetainPtr<WKTypeRef> pageOverlayParameter = 0; 201 202 if ([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) { 203 NSPoint point = [self _convertScreenPointToRootView:[(NSValue *)parameter pointValue]]; 204 pageOverlayParameter = WKPointCreate(WKPointMake(point.x, point.y)); 205 } 206 207 WKRetainPtr<WKStringRef> attributeRef = adoptWK(WKStringCreateWithCFString((CFStringRef)attribute)); 208 WKRetainPtr<WKTypeRef> result = adoptWK(m_page->pageOverlayCopyAccessibilityAttributeValue(attributeRef.get(), pageOverlayParameter.get())); 209 if (!result) 210 return nil; 211 212 if (toImpl(result.get())->type() == API::String::APIType) 213 return CFBridgingRelease(WKStringCopyCFString(kCFAllocatorDefault, (WKStringRef)result.get())); 214 else if (toImpl(result.get())->type() == API::Boolean::APIType) 215 return [NSNumber numberWithBool:WKBooleanGetValue(static_cast<WKBooleanRef>(result.get()))]; 216 217 return nil; 218} 219 220- (BOOL)accessibilityShouldUseUniqueId 221{ 222 return YES; 223} 224 225#pragma clang diagnostic push 226#pragma clang diagnostic ignored "-Wdeprecated-declarations" 227- (id)accessibilityHitTest:(NSPoint)point 228{ 229 // Hit-test point comes in as bottom-screen coordinates. Needs to be normalized to the frame of the web page. 230 NSPoint remotePosition = [[self accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue]; 231 NSSize remoteSize = [[self accessibilityAttributeValue:NSAccessibilitySizeAttribute] sizeValue]; 232 233 // Get the y position of the WKView (we have to screen-flip and go from bottom left to top left). 234 CGFloat screenHeight = [(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame].size.height; 235 remotePosition.y = (screenHeight - remotePosition.y) - remoteSize.height; 236 237 point.y = screenHeight - point.y; 238 239 // Re-center point into the web page's frame. 240 point.y -= remotePosition.y; 241 point.x -= remotePosition.x; 242 243 WebCore::FrameView* frameView = m_page ? m_page->mainFrameView() : 0; 244 if (frameView) { 245 point.y += frameView->scrollPosition().y(); 246 point.x += frameView->scrollPosition().x(); 247 } 248 249 return [[self accessibilityRootObjectWrapper] accessibilityHitTest:point]; 250} 251#pragma clang diagnostic pop 252 253- (id)accessibilityFocusedUIElement 254{ 255 return [[self accessibilityRootObjectWrapper] accessibilityFocusedUIElement]; 256} 257 258@end 259 260#endif // PLATFORM(MAC) 261