diff options
author | hajimehoshi@chromium.org <hajimehoshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-27 14:54:12 +0000 |
---|---|---|
committer | hajimehoshi@chromium.org <hajimehoshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-27 14:54:12 +0000 |
commit | 36e66360086cd1e015f0721b898debb9c0e724d0 (patch) | |
tree | 2ba2574161a68da6573d8738ca37cbcb29da41b7 /content/shell/renderer | |
parent | 0df555e1d98032506a1984cba3f855dce929948b (diff) | |
download | chromium_src-36e66360086cd1e015f0721b898debb9c0e724d0.zip chromium_src-36e66360086cd1e015f0721b898debb9c0e724d0.tar.gz chromium_src-36e66360086cd1e015f0721b898debb9c0e724d0.tar.bz2 |
Move WebAXObjectProxy and AccessibleController from CppBoundClass to gin::Wrappable
BUG=297480, 331301
Review URL: https://codereview.chromium.org/172263002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253821 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/shell/renderer')
12 files changed, 1607 insertions, 1595 deletions
diff --git a/content/shell/renderer/test_runner/AccessibilityController.cpp b/content/shell/renderer/test_runner/AccessibilityController.cpp deleted file mode 100644 index fcf4951..0000000 --- a/content/shell/renderer/test_runner/AccessibilityController.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/shell/renderer/test_runner/AccessibilityController.h" - -#include "content/shell/renderer/test_runner/WebTestDelegate.h" -#include "third_party/WebKit/public/platform/WebCString.h" -#include "third_party/WebKit/public/web/WebAXObject.h" -#include "third_party/WebKit/public/web/WebElement.h" -#include "third_party/WebKit/public/web/WebFrame.h" -#include "third_party/WebKit/public/web/WebNode.h" -#include "third_party/WebKit/public/web/WebView.h" - -using namespace blink; - -namespace WebTestRunner { - -AccessibilityController::AccessibilityController() - : m_logAccessibilityEvents(false) -{ - - bindMethod("logAccessibilityEvents", &AccessibilityController::logAccessibilityEventsCallback); - bindMethod("addNotificationListener", &AccessibilityController::addNotificationListenerCallback); - bindMethod("removeNotificationListener", &AccessibilityController::removeNotificationListenerCallback); - - bindProperty("focusedElement", &AccessibilityController::focusedElementGetterCallback); - bindProperty("rootElement", &AccessibilityController::rootElementGetterCallback); - - bindMethod("accessibleElementById", &AccessibilityController::accessibleElementByIdGetterCallback); - - bindFallbackMethod(&AccessibilityController::fallbackCallback); -} - -AccessibilityController::~AccessibilityController() -{ -} - -void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname) -{ - WebAXObject::enableAccessibility(); - WebAXObject::enableInlineTextBoxAccessibility(); - CppBoundClass::bindToJavascript(frame, classname); -} - -void AccessibilityController::reset() -{ - m_rootElement = WebAXObject(); - m_focusedElement = WebAXObject(); - m_elements.clear(); - m_notificationCallbacks.clear(); - - m_logAccessibilityEvents = false; -} - -void AccessibilityController::setFocusedElement(const WebAXObject& focusedElement) -{ - m_focusedElement = focusedElement; -} - -WebAXObjectProxy* AccessibilityController::getFocusedElement() -{ - if (m_focusedElement.isNull()) - m_focusedElement = m_webView->accessibilityObject(); - return m_elements.getOrCreate(m_focusedElement); -} - -WebAXObjectProxy* AccessibilityController::getRootElement() -{ - if (m_rootElement.isNull()) - m_rootElement = m_webView->accessibilityObject(); - return m_elements.createRoot(m_rootElement); -} - -WebAXObjectProxy* AccessibilityController::findAccessibleElementByIdRecursive(const WebAXObject& obj, const WebString& id) -{ - if (obj.isNull() || obj.isDetached()) - return 0; - - WebNode node = obj.node(); - if (!node.isNull() && node.isElementNode()) { - WebElement element = node.to<WebElement>(); - element.getAttribute("id"); - if (element.getAttribute("id") == id) - return m_elements.getOrCreate(obj); - } - - unsigned childCount = obj.childCount(); - for (unsigned i = 0; i < childCount; i++) { - if (WebAXObjectProxy* result = findAccessibleElementByIdRecursive(obj.childAt(i), id)) - return result; - } - - return 0; -} - -WebAXObjectProxy* AccessibilityController::getAccessibleElementById(const std::string& id) -{ - if (m_rootElement.isNull()) - m_rootElement = m_webView->accessibilityObject(); - - if (!m_rootElement.updateBackingStoreAndCheckValidity()) - return 0; - - return findAccessibleElementByIdRecursive(m_rootElement, WebString::fromUTF8(id.c_str())); -} - -bool AccessibilityController::shouldLogAccessibilityEvents() -{ - return m_logAccessibilityEvents; -} - -void AccessibilityController::notificationReceived(const blink::WebAXObject& target, const char* notificationName) -{ - // Call notification listeners on the element. - WebAXObjectProxy* element = m_elements.getOrCreate(target); - element->notificationReceived(notificationName); - - // Call global notification listeners. - size_t callbackCount = m_notificationCallbacks.size(); - for (size_t i = 0; i < callbackCount; i++) { - CppVariant arguments[2]; - arguments[0].set(*element->getAsCppVariant()); - arguments[1].set(notificationName); - CppVariant invokeResult; - m_notificationCallbacks[i].invokeDefault(arguments, 2, invokeResult); - } -} - -void AccessibilityController::logAccessibilityEventsCallback(const CppArgumentList&, CppVariant* result) -{ - m_logAccessibilityEvents = true; - result->setNull(); -} - -void AccessibilityController::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (arguments.size() < 1 || !arguments[0].isObject()) { - result->setNull(); - return; - } - - m_notificationCallbacks.push_back(arguments[0]); - result->setNull(); -} - -void AccessibilityController::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result) -{ - // FIXME: Implement this. - result->setNull(); -} - -void AccessibilityController::focusedElementGetterCallback(CppVariant* result) -{ - result->set(*(getFocusedElement()->getAsCppVariant())); -} - -void AccessibilityController::rootElementGetterCallback(CppVariant* result) -{ - result->set(*(getRootElement()->getAsCppVariant())); -} - -void AccessibilityController::accessibleElementByIdGetterCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() < 1 || !arguments[0].isString()) - return; - - std::string id = arguments[0].toString(); - WebAXObjectProxy* foundElement = getAccessibleElementById(id); - if (!foundElement) - return; - - result->set(*(foundElement->getAsCppVariant())); -} - -void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result) -{ - m_delegate->printMessage("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on AccessibilityController\n"); - result->setNull(); -} - -} diff --git a/content/shell/renderer/test_runner/AccessibilityController.h b/content/shell/renderer/test_runner/AccessibilityController.h deleted file mode 100644 index 976616a9..0000000 --- a/content/shell/renderer/test_runner/AccessibilityController.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_ACCESSIBILITYCONTROLLER_H_ -#define CONTENT_SHELL_RENDERER_TEST_RUNNER_ACCESSIBILITYCONTROLLER_H_ - -#include "content/shell/renderer/test_runner/CppBoundClass.h" -#include "content/shell/renderer/test_runner/WebAXObjectProxy.h" - -namespace blink { -class WebAXObject; -class WebFrame; -class WebView; -} - -namespace WebTestRunner { - -class WebTestDelegate; - -class AccessibilityController : public CppBoundClass { -public: - AccessibilityController(); - virtual ~AccessibilityController(); - - // Shadow to include accessibility initialization. - void bindToJavascript(blink::WebFrame*, const blink::WebString& classname); - void reset(); - - void setFocusedElement(const blink::WebAXObject&); - WebAXObjectProxy* getFocusedElement(); - WebAXObjectProxy* getRootElement(); - WebAXObjectProxy* getAccessibleElementById(const std::string& id); - - bool shouldLogAccessibilityEvents(); - - void notificationReceived(const blink::WebAXObject& target, const char* notificationName); - - void setDelegate(WebTestDelegate* delegate) { m_delegate = delegate; } - void setWebView(blink::WebView* webView) { m_webView = webView; } - -private: - // If true, will log all accessibility notifications. - bool m_logAccessibilityEvents; - - // Bound methods and properties - void logAccessibilityEventsCallback(const CppArgumentList&, CppVariant*); - void fallbackCallback(const CppArgumentList&, CppVariant*); - void addNotificationListenerCallback(const CppArgumentList&, CppVariant*); - void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*); - - void focusedElementGetterCallback(CppVariant*); - void rootElementGetterCallback(CppVariant*); - void accessibleElementByIdGetterCallback(const CppArgumentList&, CppVariant*); - - WebAXObjectProxy* findAccessibleElementByIdRecursive(const blink::WebAXObject&, const blink::WebString& id); - - blink::WebAXObject m_focusedElement; - blink::WebAXObject m_rootElement; - - WebAXObjectProxyList m_elements; - - std::vector<CppVariant> m_notificationCallbacks; - - WebTestDelegate* m_delegate; - blink::WebView* m_webView; -}; - -} - -#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_ACCESSIBILITYCONTROLLER_H_ diff --git a/content/shell/renderer/test_runner/TestInterfaces.cpp b/content/shell/renderer/test_runner/TestInterfaces.cpp index 426f652..277de98 100644 --- a/content/shell/renderer/test_runner/TestInterfaces.cpp +++ b/content/shell/renderer/test_runner/TestInterfaces.cpp @@ -7,10 +7,10 @@ #include <string> #include "base/strings/stringprintf.h" -#include "content/shell/renderer/test_runner/AccessibilityController.h" #include "content/shell/renderer/test_runner/EventSender.h" #include "content/shell/renderer/test_runner/TestRunner.h" #include "content/shell/renderer/test_runner/WebTestProxy.h" +#include "content/shell/renderer/test_runner/accessibility_controller.h" #include "content/shell/renderer/test_runner/gamepad_controller.h" #include "content/shell/renderer/test_runner/text_input_controller.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -26,7 +26,7 @@ using namespace std; namespace WebTestRunner { TestInterfaces::TestInterfaces() - : m_accessibilityController(new AccessibilityController()) + : m_accessibilityController(new content::AccessibilityController()) , m_eventSender(new EventSender(this)) , m_gamepadController(new content::GamepadController()) , m_textInputController(new content::TextInputController()) @@ -43,13 +43,13 @@ TestInterfaces::TestInterfaces() TestInterfaces::~TestInterfaces() { - m_accessibilityController->setWebView(0); + m_accessibilityController->SetWebView(0); m_eventSender->setWebView(0); // m_gamepadController doesn't depend on WebView. m_textInputController->SetWebView(NULL); m_testRunner->setWebView(0, 0); - m_accessibilityController->setDelegate(0); + m_accessibilityController->SetDelegate(0); m_eventSender->setDelegate(0); m_gamepadController->SetDelegate(0); // m_textInputController doesn't depend on WebTestDelegate. @@ -59,7 +59,7 @@ TestInterfaces::~TestInterfaces() void TestInterfaces::setWebView(WebView* webView, WebTestProxyBase* proxy) { m_proxy = proxy; - m_accessibilityController->setWebView(webView); + m_accessibilityController->SetWebView(webView); m_eventSender->setWebView(webView); // m_gamepadController doesn't depend on WebView. m_textInputController->SetWebView(webView); @@ -68,7 +68,7 @@ void TestInterfaces::setWebView(WebView* webView, WebTestProxyBase* proxy) void TestInterfaces::setDelegate(WebTestDelegate* delegate) { - m_accessibilityController->setDelegate(delegate); + m_accessibilityController->SetDelegate(delegate); m_eventSender->setDelegate(delegate); m_gamepadController->SetDelegate(delegate); // m_textInputController doesn't depend on WebTestDelegate. @@ -78,7 +78,7 @@ void TestInterfaces::setDelegate(WebTestDelegate* delegate) void TestInterfaces::bindTo(WebFrame* frame) { - m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController")); + m_accessibilityController->Install(frame); m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender")); m_gamepadController->Install(frame); m_textInputController->Install(frame); @@ -88,7 +88,7 @@ void TestInterfaces::bindTo(WebFrame* frame) void TestInterfaces::resetTestHelperControllers() { - m_accessibilityController->reset(); + m_accessibilityController->Reset(); m_eventSender->reset(); m_gamepadController->Reset(); // m_textInputController doesn't have any state to reset. @@ -153,7 +153,7 @@ void TestInterfaces::windowClosed(WebTestProxyBase* proxy) m_windowList.erase(pos); } -AccessibilityController* TestInterfaces::accessibilityController() +content::AccessibilityController* TestInterfaces::accessibilityController() { return m_accessibilityController.get(); } diff --git a/content/shell/renderer/test_runner/TestInterfaces.h b/content/shell/renderer/test_runner/TestInterfaces.h index 69e490c..21c6d6a 100644 --- a/content/shell/renderer/test_runner/TestInterfaces.h +++ b/content/shell/renderer/test_runner/TestInterfaces.h @@ -25,13 +25,13 @@ class WebView; } namespace content { +class AccessibilityController; class GamepadController; class TextInputController; } namespace WebTestRunner { -class AccessibilityController; class EventSender; class TestRunner; class WebTestDelegate; @@ -53,7 +53,7 @@ public: void windowOpened(WebTestProxyBase*); void windowClosed(WebTestProxyBase*); - AccessibilityController* accessibilityController(); + content::AccessibilityController* accessibilityController(); EventSender* eventSender(); TestRunner* testRunner(); WebTestDelegate* delegate(); @@ -62,7 +62,7 @@ public: blink::WebThemeEngine* themeEngine(); private: - scoped_ptr<AccessibilityController> m_accessibilityController; + scoped_ptr<content::AccessibilityController> m_accessibilityController; scoped_ptr<EventSender> m_eventSender; scoped_ptr<content::GamepadController> m_gamepadController; scoped_ptr<content::TextInputController> m_textInputController; diff --git a/content/shell/renderer/test_runner/WebAXObjectProxy.cpp b/content/shell/renderer/test_runner/WebAXObjectProxy.cpp deleted file mode 100644 index 1690fee..0000000 --- a/content/shell/renderer/test_runner/WebAXObjectProxy.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/shell/renderer/test_runner/WebAXObjectProxy.h" - -#include "content/shell/renderer/test_runner/TestCommon.h" -#include "third_party/WebKit/public/platform/WebCString.h" -#include "third_party/WebKit/public/platform/WebPoint.h" -#include "third_party/WebKit/public/platform/WebRect.h" -#include "third_party/WebKit/public/platform/WebString.h" - -using namespace blink; -using namespace std; - -namespace WebTestRunner { - -namespace { - -// Map role value to string, matching Safari/Mac platform implementation to -// avoid rebaselining layout tests. -string roleToString(WebAXRole role) -{ - string result = "AXRole: AX"; - switch (role) { - case WebAXRoleAlertDialog: - return result.append("AlertDialog"); - case WebAXRoleAlert: - return result.append("Alert"); - case WebAXRoleAnnotation: - return result.append("Annotation"); - case WebAXRoleApplication: - return result.append("Application"); - case WebAXRoleArticle: - return result.append("Article"); - case WebAXRoleBanner: - return result.append("Banner"); - case WebAXRoleBrowser: - return result.append("Browser"); - case WebAXRoleBusyIndicator: - return result.append("BusyIndicator"); - case WebAXRoleButton: - return result.append("Button"); - case WebAXRoleCanvas: - return result.append("Canvas"); - case WebAXRoleCell: - return result.append("Cell"); - case WebAXRoleCheckBox: - return result.append("CheckBox"); - case WebAXRoleColorWell: - return result.append("ColorWell"); - case WebAXRoleColumnHeader: - return result.append("ColumnHeader"); - case WebAXRoleColumn: - return result.append("Column"); - case WebAXRoleComboBox: - return result.append("ComboBox"); - case WebAXRoleComplementary: - return result.append("Complementary"); - case WebAXRoleContentInfo: - return result.append("ContentInfo"); - case WebAXRoleDefinition: - return result.append("Definition"); - case WebAXRoleDescriptionListDetail: - return result.append("DescriptionListDetail"); - case WebAXRoleDescriptionListTerm: - return result.append("DescriptionListTerm"); - case WebAXRoleDialog: - return result.append("Dialog"); - case WebAXRoleDirectory: - return result.append("Directory"); - case WebAXRoleDisclosureTriangle: - return result.append("DisclosureTriangle"); - case WebAXRoleDiv: - return result.append("Div"); - case WebAXRoleDocument: - return result.append("Document"); - case WebAXRoleDrawer: - return result.append("Drawer"); - case WebAXRoleEditableText: - return result.append("EditableText"); - case WebAXRoleFooter: - return result.append("Footer"); - case WebAXRoleForm: - return result.append("Form"); - case WebAXRoleGrid: - return result.append("Grid"); - case WebAXRoleGroup: - return result.append("Group"); - case WebAXRoleGrowArea: - return result.append("GrowArea"); - case WebAXRoleHeading: - return result.append("Heading"); - case WebAXRoleHelpTag: - return result.append("HelpTag"); - case WebAXRoleHorizontalRule: - return result.append("HorizontalRule"); - case WebAXRoleIgnored: - return result.append("Ignored"); - case WebAXRoleImageMapLink: - return result.append("ImageMapLink"); - case WebAXRoleImageMap: - return result.append("ImageMap"); - case WebAXRoleImage: - return result.append("Image"); - case WebAXRoleIncrementor: - return result.append("Incrementor"); - case WebAXRoleInlineTextBox: - return result.append("InlineTextBox"); - case WebAXRoleLabel: - return result.append("Label"); - case WebAXRoleLegend: - return result.append("Legend"); - case WebAXRoleLink: - return result.append("Link"); - case WebAXRoleListBoxOption: - return result.append("ListBoxOption"); - case WebAXRoleListBox: - return result.append("ListBox"); - case WebAXRoleListItem: - return result.append("ListItem"); - case WebAXRoleListMarker: - return result.append("ListMarker"); - case WebAXRoleList: - return result.append("List"); - case WebAXRoleLog: - return result.append("Log"); - case WebAXRoleMain: - return result.append("Main"); - case WebAXRoleMarquee: - return result.append("Marquee"); - case WebAXRoleMathElement: - return result.append("MathElement"); - case WebAXRoleMath: - return result.append("Math"); - case WebAXRoleMatte: - return result.append("Matte"); - case WebAXRoleMenuBar: - return result.append("MenuBar"); - case WebAXRoleMenuButton: - return result.append("MenuButton"); - case WebAXRoleMenuItem: - return result.append("MenuItem"); - case WebAXRoleMenuListOption: - return result.append("MenuListOption"); - case WebAXRoleMenuListPopup: - return result.append("MenuListPopup"); - case WebAXRoleMenu: - return result.append("Menu"); - case WebAXRoleNavigation: - return result.append("Navigation"); - case WebAXRoleNote: - return result.append("Note"); - case WebAXRoleOutline: - return result.append("Outline"); - case WebAXRoleParagraph: - return result.append("Paragraph"); - case WebAXRolePopUpButton: - return result.append("PopUpButton"); - case WebAXRolePresentational: - return result.append("Presentational"); - case WebAXRoleProgressIndicator: - return result.append("ProgressIndicator"); - case WebAXRoleRadioButton: - return result.append("RadioButton"); - case WebAXRoleRadioGroup: - return result.append("RadioGroup"); - case WebAXRoleRegion: - return result.append("Region"); - case WebAXRoleRootWebArea: - return result.append("RootWebArea"); - case WebAXRoleRowHeader: - return result.append("RowHeader"); - case WebAXRoleRow: - return result.append("Row"); - case WebAXRoleRulerMarker: - return result.append("RulerMarker"); - case WebAXRoleRuler: - return result.append("Ruler"); - case WebAXRoleSVGRoot: - return result.append("SVGRoot"); - case WebAXRoleScrollArea: - return result.append("ScrollArea"); - case WebAXRoleScrollBar: - return result.append("ScrollBar"); - case WebAXRoleSeamlessWebArea: - return result.append("SeamlessWebArea"); - case WebAXRoleSearch: - return result.append("Search"); - case WebAXRoleSheet: - return result.append("Sheet"); - case WebAXRoleSlider: - return result.append("Slider"); - case WebAXRoleSliderThumb: - return result.append("SliderThumb"); - case WebAXRoleSpinButtonPart: - return result.append("SpinButtonPart"); - case WebAXRoleSpinButton: - return result.append("SpinButton"); - case WebAXRoleSplitGroup: - return result.append("SplitGroup"); - case WebAXRoleSplitter: - return result.append("Splitter"); - case WebAXRoleStaticText: - return result.append("StaticText"); - case WebAXRoleStatus: - return result.append("Status"); - case WebAXRoleSystemWide: - return result.append("SystemWide"); - case WebAXRoleTabGroup: - return result.append("TabGroup"); - case WebAXRoleTabList: - return result.append("TabList"); - case WebAXRoleTabPanel: - return result.append("TabPanel"); - case WebAXRoleTab: - return result.append("Tab"); - case WebAXRoleTableHeaderContainer: - return result.append("TableHeaderContainer"); - case WebAXRoleTable: - return result.append("Table"); - case WebAXRoleTextArea: - return result.append("TextArea"); - case WebAXRoleTextField: - return result.append("TextField"); - case WebAXRoleTimer: - return result.append("Timer"); - case WebAXRoleToggleButton: - return result.append("ToggleButton"); - case WebAXRoleToolbar: - return result.append("Toolbar"); - case WebAXRoleTreeGrid: - return result.append("TreeGrid"); - case WebAXRoleTreeItem: - return result.append("TreeItem"); - case WebAXRoleTree: - return result.append("Tree"); - case WebAXRoleUnknown: - return result.append("Unknown"); - case WebAXRoleUserInterfaceTooltip: - return result.append("UserInterfaceTooltip"); - case WebAXRoleValueIndicator: - return result.append("ValueIndicator"); - case WebAXRoleWebArea: - return result.append("WebArea"); - case WebAXRoleWindow: - return result.append("Window"); - default: - return result.append("Unknown"); - } -} - -string getDescription(const WebAXObject& object) -{ - string description = object.accessibilityDescription().utf8(); - return description.insert(0, "AXDescription: "); -} - -string getHelpText(const WebAXObject& object) -{ - string helpText = object.helpText().utf8(); - return helpText.insert(0, "AXHelp: "); -} - -string getStringValue(const WebAXObject& object) -{ - string value; - if (object.role() == WebAXRoleColorWell) { - int r, g, b; - char buffer[100]; - object.colorValue(r, g, b); - snprintf(buffer, sizeof(buffer), "rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.); - value = buffer; - } else { - value = object.stringValue().utf8(); - } - return value.insert(0, "AXValue: "); -} - -string getRole(const WebAXObject& object) -{ - string roleString = roleToString(object.role()); - - // Special-case canvas with fallback content because Chromium wants to - // treat this as essentially a separate role that it can map differently depending - // on the platform. - if (object.role() == WebAXRoleCanvas && object.canvasHasFallbackContent()) - roleString += "WithFallbackContent"; - - return roleString; -} - -string getTitle(const WebAXObject& object) -{ - string title = object.title().utf8(); - return title.insert(0, "AXTitle: "); -} - -string getOrientation(const WebAXObject& object) -{ - if (object.isVertical()) - return "AXOrientation: AXVerticalOrientation"; - - return "AXOrientation: AXHorizontalOrientation"; -} - -string getValueDescription(const WebAXObject& object) -{ - string valueDescription = object.valueDescription().utf8(); - return valueDescription.insert(0, "AXValueDescription: "); -} - -string getAttributes(const WebAXObject& object) -{ - // FIXME: Concatenate all attributes of the AXObject. - string attributes(getTitle(object)); - attributes.append("\n"); - attributes.append(getRole(object)); - attributes.append("\n"); - attributes.append(getDescription(object)); - return attributes; -} - -WebRect boundsForCharacter(const WebAXObject& object, int characterIndex) -{ - BLINK_ASSERT(object.role() == WebAXRoleStaticText); - int end = 0; - for (unsigned i = 0; i < object.childCount(); i++) { - WebAXObject inlineTextBox = object.childAt(i); - BLINK_ASSERT(inlineTextBox.role() == WebAXRoleInlineTextBox); - int start = end; - end += inlineTextBox.stringValue().length(); - if (end <= characterIndex) - continue; - WebRect inlineTextBoxRect = inlineTextBox.boundingBoxRect(); - int localIndex = characterIndex - start; - WebVector<int> characterOffsets; - inlineTextBox.characterOffsets(characterOffsets); - BLINK_ASSERT(characterOffsets.size() > 0 && characterOffsets.size() == inlineTextBox.stringValue().length()); - switch (inlineTextBox.textDirection()) { - case WebAXTextDirectionLR: { - if (localIndex) { - int left = inlineTextBoxRect.x + characterOffsets[localIndex - 1]; - int width = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; - return WebRect(left, inlineTextBoxRect.y, width, inlineTextBoxRect.height); - } - return WebRect(inlineTextBoxRect.x, inlineTextBoxRect.y, characterOffsets[0], inlineTextBoxRect.height); - } - case WebAXTextDirectionRL: { - int right = inlineTextBoxRect.x + inlineTextBoxRect.width; - - if (localIndex) { - int left = right - characterOffsets[localIndex]; - int width = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; - return WebRect(left, inlineTextBoxRect.y, width, inlineTextBoxRect.height); - } - int left = right - characterOffsets[0]; - return WebRect(left, inlineTextBoxRect.y, characterOffsets[0], inlineTextBoxRect.height); - } - case WebAXTextDirectionTB: { - if (localIndex) { - int top = inlineTextBoxRect.y + characterOffsets[localIndex - 1]; - int height = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; - return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, height); - } - return WebRect(inlineTextBoxRect.x, inlineTextBoxRect.y, inlineTextBoxRect.width, characterOffsets[0]); - } - case WebAXTextDirectionBT: { - int bottom = inlineTextBoxRect.y + inlineTextBoxRect.height; - - if (localIndex) { - int top = bottom - characterOffsets[localIndex]; - int height = characterOffsets[localIndex] - characterOffsets[localIndex - 1]; - return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, height); - } - int top = bottom - characterOffsets[0]; - return WebRect(inlineTextBoxRect.x, top, inlineTextBoxRect.width, characterOffsets[0]); - } - } - } - - BLINK_ASSERT(false); - return WebRect(); -} - -void getBoundariesForOneWord(const WebAXObject& object, int characterIndex, int& wordStart, int& wordEnd) -{ - int end = 0; - for (unsigned i = 0; i < object.childCount(); i++) { - WebAXObject inlineTextBox = object.childAt(i); - BLINK_ASSERT(inlineTextBox.role() == WebAXRoleInlineTextBox); - int start = end; - end += inlineTextBox.stringValue().length(); - if (end <= characterIndex) - continue; - int localIndex = characterIndex - start; - - WebVector<int> starts; - WebVector<int> ends; - inlineTextBox.wordBoundaries(starts, ends); - size_t wordCount = starts.size(); - BLINK_ASSERT(ends.size() == wordCount); - - // If there are no words, use the InlineTextBox boundaries. - if (!wordCount) { - wordStart = start; - wordEnd = end; - return; - } - - // Look for a character within any word other than the last. - for (size_t j = 0; j < wordCount - 1; j++) { - if (localIndex <= ends[j]) { - wordStart = start + starts[j]; - wordEnd = start + ends[j]; - return; - } - } - - // Return the last word by default. - wordStart = start + starts[wordCount - 1]; - wordEnd = start + ends[wordCount - 1]; - return; - } -} - -// Collects attributes into a string, delimited by dashes. Used by all methods -// that output lists of attributes: attributesOfLinkedUIElementsCallback, -// AttributesOfChildrenCallback, etc. -class AttributesCollector { -public: - void collectAttributes(const WebAXObject& object) - { - m_attributes.append("\n------------\n"); - m_attributes.append(getAttributes(object)); - } - - string attributes() const { return m_attributes; } - -private: - string m_attributes; -}; - -} - -WebAXObjectProxy::WebAXObjectProxy(const WebAXObject& object, Factory* factory) - : m_accessibilityObject(object) - , m_factory(factory) -{ - - BLINK_ASSERT(factory); - - // - // Properties - // - - bindProperty("role", &WebAXObjectProxy::roleGetterCallback); - bindProperty("title", &WebAXObjectProxy::titleGetterCallback); - bindProperty("description", &WebAXObjectProxy::descriptionGetterCallback); - bindProperty("helpText", &WebAXObjectProxy::helpTextGetterCallback); - bindProperty("stringValue", &WebAXObjectProxy::stringValueGetterCallback); - bindProperty("x", &WebAXObjectProxy::xGetterCallback); - bindProperty("y", &WebAXObjectProxy::yGetterCallback); - bindProperty("width", &WebAXObjectProxy::widthGetterCallback); - bindProperty("height", &WebAXObjectProxy::heightGetterCallback); - bindProperty("intValue", &WebAXObjectProxy::intValueGetterCallback); - bindProperty("minValue", &WebAXObjectProxy::minValueGetterCallback); - bindProperty("maxValue", &WebAXObjectProxy::maxValueGetterCallback); - bindProperty("valueDescription", &WebAXObjectProxy::valueDescriptionGetterCallback); - bindProperty("childrenCount", &WebAXObjectProxy::childrenCountGetterCallback); - bindProperty("insertionPointLineNumber", &WebAXObjectProxy::insertionPointLineNumberGetterCallback); - bindProperty("selectedTextRange", &WebAXObjectProxy::selectedTextRangeGetterCallback); - bindProperty("isEnabled", &WebAXObjectProxy::isEnabledGetterCallback); - bindProperty("isRequired", &WebAXObjectProxy::isRequiredGetterCallback); - bindProperty("isFocused", &WebAXObjectProxy::isFocusedGetterCallback); - bindProperty("isFocusable", &WebAXObjectProxy::isFocusableGetterCallback); - bindProperty("isSelected", &WebAXObjectProxy::isSelectedGetterCallback); - bindProperty("isSelectable", &WebAXObjectProxy::isSelectableGetterCallback); - bindProperty("isMultiSelectable", &WebAXObjectProxy::isMultiSelectableGetterCallback); - bindProperty("isSelectedOptionActive", &WebAXObjectProxy::isSelectedOptionActiveGetterCallback); - bindProperty("isExpanded", &WebAXObjectProxy::isExpandedGetterCallback); - bindProperty("isChecked", &WebAXObjectProxy::isCheckedGetterCallback); - bindProperty("isVisible", &WebAXObjectProxy::isVisibleGetterCallback); - bindProperty("isOffScreen", &WebAXObjectProxy::isOffScreenGetterCallback); - bindProperty("isCollapsed", &WebAXObjectProxy::isCollapsedGetterCallback); - bindProperty("hasPopup", &WebAXObjectProxy::hasPopupGetterCallback); - bindProperty("isValid", &WebAXObjectProxy::isValidGetterCallback); - bindProperty("isReadOnly", &WebAXObjectProxy::isReadOnlyGetterCallback); - bindProperty("orientation", &WebAXObjectProxy::orientationGetterCallback); - bindProperty("clickPointX", &WebAXObjectProxy::clickPointXGetterCallback); - bindProperty("clickPointY", &WebAXObjectProxy::clickPointYGetterCallback); - bindProperty("rowCount", &WebAXObjectProxy::rowCountGetterCallback); - bindProperty("columnCount", &WebAXObjectProxy::columnCountGetterCallback); - bindProperty("isClickable", &WebAXObjectProxy::isClickableGetterCallback); - - // - // Methods - // - - bindMethod("allAttributes", &WebAXObjectProxy::allAttributesCallback); - bindMethod("attributesOfChildren", &WebAXObjectProxy::attributesOfChildrenCallback); - bindMethod("lineForIndex", &WebAXObjectProxy::lineForIndexCallback); - bindMethod("boundsForRange", &WebAXObjectProxy::boundsForRangeCallback); - bindMethod("childAtIndex", &WebAXObjectProxy::childAtIndexCallback); - bindMethod("elementAtPoint", &WebAXObjectProxy::elementAtPointCallback); - bindMethod("tableHeader", &WebAXObjectProxy::tableHeaderCallback); - bindMethod("rowIndexRange", &WebAXObjectProxy::rowIndexRangeCallback); - bindMethod("columnIndexRange", &WebAXObjectProxy::columnIndexRangeCallback); - bindMethod("cellForColumnAndRow", &WebAXObjectProxy::cellForColumnAndRowCallback); - bindMethod("titleUIElement", &WebAXObjectProxy::titleUIElementCallback); - bindMethod("setSelectedTextRange", &WebAXObjectProxy::setSelectedTextRangeCallback); - bindMethod("isAttributeSettable", &WebAXObjectProxy::isAttributeSettableCallback); - bindMethod("isPressActionSupported", &WebAXObjectProxy::isPressActionSupportedCallback); - bindMethod("isIncrementActionSupported", &WebAXObjectProxy::isIncrementActionSupportedCallback); - bindMethod("isDecrementActionSupported", &WebAXObjectProxy::isDecrementActionSupportedCallback); - bindMethod("parentElement", &WebAXObjectProxy::parentElementCallback); - bindMethod("increment", &WebAXObjectProxy::incrementCallback); - bindMethod("decrement", &WebAXObjectProxy::decrementCallback); - bindMethod("showMenu", &WebAXObjectProxy::showMenuCallback); - bindMethod("press", &WebAXObjectProxy::pressCallback); - bindMethod("isEqual", &WebAXObjectProxy::isEqualCallback); - bindMethod("addNotificationListener", &WebAXObjectProxy::addNotificationListenerCallback); - bindMethod("removeNotificationListener", &WebAXObjectProxy::removeNotificationListenerCallback); - bindMethod("takeFocus", &WebAXObjectProxy::takeFocusCallback); - bindMethod("scrollToMakeVisible", &WebAXObjectProxy::scrollToMakeVisibleCallback); - bindMethod("scrollToMakeVisibleWithSubFocus", &WebAXObjectProxy::scrollToMakeVisibleWithSubFocusCallback); - bindMethod("scrollToGlobalPoint", &WebAXObjectProxy::scrollToGlobalPointCallback); - bindMethod("wordStart", &WebAXObjectProxy::wordStartCallback); - bindMethod("wordEnd", &WebAXObjectProxy::wordEndCallback); - - bindFallbackMethod(&WebAXObjectProxy::fallbackCallback); -} - -WebAXObjectProxy::~WebAXObjectProxy() -{ -} - -WebAXObjectProxy* WebAXObjectProxy::getChildAtIndex(unsigned index) -{ - return m_factory->getOrCreate(accessibilityObject().childAt(index)); -} - -bool WebAXObjectProxy::isRoot() const -{ - return false; -} - -bool WebAXObjectProxy::isEqual(const blink::WebAXObject& other) -{ - return accessibilityObject().equals(other); -} - -void WebAXObjectProxy::notificationReceived(const char* notificationName) -{ - size_t callbackCount = m_notificationCallbacks.size(); - for (size_t i = 0; i < callbackCount; i++) { - CppVariant notificationNameArgument; - notificationNameArgument.set(notificationName); - CppVariant invokeResult; - m_notificationCallbacks[i].invokeDefault(¬ificationNameArgument, 1, invokeResult); - } -} - -// -// Properties -// - -void WebAXObjectProxy::roleGetterCallback(CppVariant* result) -{ - result->set(getRole(accessibilityObject())); -} - -void WebAXObjectProxy::titleGetterCallback(CppVariant* result) -{ - result->set(getTitle(accessibilityObject())); -} - -void WebAXObjectProxy::descriptionGetterCallback(CppVariant* result) -{ - result->set(getDescription(accessibilityObject())); -} - -void WebAXObjectProxy::helpTextGetterCallback(CppVariant* result) -{ - result->set(getHelpText(accessibilityObject())); -} - -void WebAXObjectProxy::stringValueGetterCallback(CppVariant* result) -{ - result->set(getStringValue(accessibilityObject())); -} - -void WebAXObjectProxy::xGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().boundingBoxRect().x); -} - -void WebAXObjectProxy::yGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().boundingBoxRect().y); -} - -void WebAXObjectProxy::widthGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().boundingBoxRect().width); -} - -void WebAXObjectProxy::heightGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().boundingBoxRect().height); -} - -void WebAXObjectProxy::intValueGetterCallback(CppVariant* result) -{ - if (accessibilityObject().supportsRangeValue()) - result->set(accessibilityObject().valueForRange()); - else if (accessibilityObject().role() == WebAXRoleHeading) - result->set(accessibilityObject().headingLevel()); - else - result->set(atoi(accessibilityObject().stringValue().utf8().data())); -} - -void WebAXObjectProxy::minValueGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().minValueForRange()); -} - -void WebAXObjectProxy::maxValueGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().maxValueForRange()); -} - -void WebAXObjectProxy::valueDescriptionGetterCallback(CppVariant* result) -{ - result->set(getValueDescription(accessibilityObject())); -} - -void WebAXObjectProxy::childrenCountGetterCallback(CppVariant* result) -{ - int count = 1; // Root object always has only one child, the WebView. - if (!isRoot()) - count = accessibilityObject().childCount(); - result->set(count); -} - -void WebAXObjectProxy::insertionPointLineNumberGetterCallback(CppVariant* result) -{ - if (!accessibilityObject().isFocused()) { - result->set(-1); - return; - } - - int lineNumber = accessibilityObject().selectionEndLineNumber(); - result->set(lineNumber); -} - -void WebAXObjectProxy::selectedTextRangeGetterCallback(CppVariant* result) -{ - unsigned selectionStart = accessibilityObject().selectionStart(); - unsigned selectionEnd = accessibilityObject().selectionEnd(); - char buffer[100]; - snprintf(buffer, sizeof(buffer), "{%d, %d}", selectionStart, selectionEnd - selectionStart); - - result->set(std::string(buffer)); -} - -void WebAXObjectProxy::isEnabledGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isEnabled()); -} - -void WebAXObjectProxy::isRequiredGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isRequired()); -} - -void WebAXObjectProxy::isFocusedGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isFocused()); -} - -void WebAXObjectProxy::isFocusableGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().canSetFocusAttribute()); -} - -void WebAXObjectProxy::isSelectedGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isSelected()); -} - -void WebAXObjectProxy::isSelectableGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().canSetSelectedAttribute()); -} - -void WebAXObjectProxy::isMultiSelectableGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isMultiSelectable()); -} - -void WebAXObjectProxy::isSelectedOptionActiveGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isSelectedOptionActive()); -} - -void WebAXObjectProxy::isExpandedGetterCallback(CppVariant* result) -{ - result->set(!accessibilityObject().isCollapsed()); -} - -void WebAXObjectProxy::isCheckedGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isChecked()); -} - -void WebAXObjectProxy::isVisibleGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isVisible()); -} - -void WebAXObjectProxy::isOffScreenGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isOffScreen()); -} - -void WebAXObjectProxy::isCollapsedGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isCollapsed()); -} - -void WebAXObjectProxy::hasPopupGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().ariaHasPopup()); -} - -void WebAXObjectProxy::isValidGetterCallback(CppVariant* result) -{ - result->set(!accessibilityObject().isDetached()); -} - -void WebAXObjectProxy::isReadOnlyGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isReadOnly()); -} - -void WebAXObjectProxy::orientationGetterCallback(CppVariant* result) -{ - result->set(getOrientation(accessibilityObject())); -} - -void WebAXObjectProxy::clickPointXGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().clickPoint().x); -} - -void WebAXObjectProxy::clickPointYGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().clickPoint().y); -} - -void WebAXObjectProxy::rowCountGetterCallback(CppVariant* result) -{ - result->set(static_cast<int32_t>(accessibilityObject().rowCount())); -} - -void WebAXObjectProxy::columnCountGetterCallback(CppVariant* result) -{ - result->set(static_cast<int32_t>(accessibilityObject().columnCount())); -} - -void WebAXObjectProxy::isClickableGetterCallback(CppVariant* result) -{ - result->set(accessibilityObject().isClickable()); -} - -// -// Methods -// - -void WebAXObjectProxy::allAttributesCallback(const CppArgumentList&, CppVariant* result) -{ - result->set(getAttributes(accessibilityObject())); -} - -void WebAXObjectProxy::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result) -{ - AttributesCollector collector; - unsigned size = accessibilityObject().childCount(); - for (unsigned i = 0; i < size; ++i) - collector.collectAttributes(accessibilityObject().childAt(i)); - result->set(collector.attributes()); -} - -void WebAXObjectProxy::lineForIndexCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (!arguments.size() || !arguments[0].isNumber()) { - result->setNull(); - return; - } - - int index = arguments[0].toInt32(); - - WebVector<int> lineBreaks; - accessibilityObject().lineBreaks(lineBreaks); - int line = 0; - int vectorSize = static_cast<int>(lineBreaks.size()); - while (line < vectorSize && lineBreaks[line] <= index) - line++; - result->set(line); -} - -void WebAXObjectProxy::boundsForRangeCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - if (accessibilityObject().role() != WebAXRoleStaticText) - return; - - int start = arguments[0].toInt32(); - int end = arguments[1].toInt32(); - int len = end - start; - - // Get the bounds for each character and union them into one large rectangle. - // This is just for testing so it doesn't need to be efficient. - WebRect bounds = boundsForCharacter(accessibilityObject(), start); - for (int i = 1; i < len; i++) { - WebRect next = boundsForCharacter(accessibilityObject(), start + i); - int right = std::max(bounds.x + bounds.width, next.x + next.width); - int bottom = std::max(bounds.y + bounds.height, next.y + next.height); - bounds.x = std::min(bounds.x, next.x); - bounds.y = std::min(bounds.y, next.y); - bounds.width = right - bounds.x; - bounds.height = bottom - bounds.y; - } - - char buffer[100]; - snprintf(buffer, sizeof(buffer), "{x: %d, y: %d, width: %d, height: %d}", bounds.x, bounds.y, bounds.width, bounds.height); - result->set(string(buffer)); -} - -void WebAXObjectProxy::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (!arguments.size() || !arguments[0].isNumber()) { - result->setNull(); - return; - } - - WebAXObjectProxy* child = getChildAtIndex(arguments[0].toInt32()); - if (!child) { - result->setNull(); - return; - } - - result->set(*(child->getAsCppVariant())); -} - -void WebAXObjectProxy::elementAtPointCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - int x = arguments[0].toInt32(); - int y = arguments[1].toInt32(); - WebPoint point(x, y); - WebAXObject obj = accessibilityObject().hitTest(point); - if (obj.isNull()) - return; - - result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); -} - -void WebAXObjectProxy::tableHeaderCallback(const CppArgumentList&, CppVariant* result) -{ - WebAXObject obj = accessibilityObject().headerContainerObject(); - if (obj.isNull()) { - result->setNull(); - return; - } - - result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); -} - -void WebAXObjectProxy::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result) -{ - unsigned rowIndex = accessibilityObject().cellRowIndex(); - unsigned rowSpan = accessibilityObject().cellRowSpan(); - char buffer[100]; - snprintf(buffer, sizeof(buffer), "{%d, %d}", rowIndex, rowSpan); - string value = buffer; - result->set(std::string(buffer)); -} - -void WebAXObjectProxy::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result) -{ - unsigned columnIndex = accessibilityObject().cellColumnIndex(); - unsigned columnSpan = accessibilityObject().cellColumnSpan(); - char buffer[100]; - snprintf(buffer, sizeof(buffer), "{%d, %d}", columnIndex, columnSpan); - result->set(std::string(buffer)); -} - -void WebAXObjectProxy::cellForColumnAndRowCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - int column = arguments[0].toInt32(); - int row = arguments[1].toInt32(); - WebAXObject obj = accessibilityObject().cellForColumnAndRow(column, row); - if (obj.isNull()) { - result->setNull(); - return; - } - - result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); -} - -void WebAXObjectProxy::titleUIElementCallback(const CppArgumentList&, CppVariant* result) -{ - WebAXObject obj = accessibilityObject().titleUIElement(); - if (obj.isNull()) { - result->setNull(); - return; - } - - result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant())); -} - -void WebAXObjectProxy::setSelectedTextRangeCallback(const CppArgumentList&arguments, CppVariant* result) -{ - result->setNull(); - if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isNumber()) - return; - - int selectionStart = arguments[0].toInt32(); - int selectionEnd = selectionStart + arguments[1].toInt32(); - accessibilityObject().setSelectedTextRange(selectionStart, selectionEnd); -} - -void WebAXObjectProxy::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (arguments.size() < 1 && !arguments[0].isString()) { - result->setNull(); - return; - } - - string attribute = arguments[0].toString(); - bool settable = false; - if (attribute == "AXValue") - settable = accessibilityObject().canSetValueAttribute(); - result->set(settable); -} - -void WebAXObjectProxy::isPressActionSupportedCallback(const CppArgumentList&, CppVariant* result) -{ - result->set(accessibilityObject().canPress()); -} - -void WebAXObjectProxy::isIncrementActionSupportedCallback(const CppArgumentList&, CppVariant* result) -{ - result->set(accessibilityObject().canIncrement()); -} - -void WebAXObjectProxy::isDecrementActionSupportedCallback(const CppArgumentList&, CppVariant* result) -{ - result->set(accessibilityObject().canDecrement()); -} - -void WebAXObjectProxy::parentElementCallback(const CppArgumentList&, CppVariant* result) -{ - WebAXObject parentObject = accessibilityObject().parentObject(); - while (parentObject.accessibilityIsIgnored()) - parentObject = parentObject.parentObject(); - WebAXObjectProxy* parent = m_factory->getOrCreate(parentObject); - if (!parent) { - result->setNull(); - return; - } - - result->set(*(parent->getAsCppVariant())); -} - -void WebAXObjectProxy::incrementCallback(const CppArgumentList&, CppVariant* result) -{ - accessibilityObject().increment(); - result->setNull(); -} - -void WebAXObjectProxy::decrementCallback(const CppArgumentList&, CppVariant* result) -{ - accessibilityObject().decrement(); - result->setNull(); -} - -void WebAXObjectProxy::showMenuCallback(const CppArgumentList&, CppVariant* result) -{ - result->setNull(); -} - -void WebAXObjectProxy::pressCallback(const CppArgumentList&, CppVariant* result) -{ - accessibilityObject().press(); - result->setNull(); -} - -void WebAXObjectProxy::isEqualCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (arguments.size() < 1 || !arguments[0].isObject()) { - result->setNull(); - return; - } - - result->set(arguments[0].isEqual(*getAsCppVariant())); -} - -void WebAXObjectProxy::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result) -{ - if (arguments.size() < 1 || !arguments[0].isObject()) { - result->setNull(); - return; - } - - m_notificationCallbacks.push_back(arguments[0]); - result->setNull(); -} - -void WebAXObjectProxy::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result) -{ - // FIXME: Implement this. - result->setNull(); -} - -void WebAXObjectProxy::takeFocusCallback(const CppArgumentList&, CppVariant* result) -{ - accessibilityObject().setFocused(true); - result->setNull(); -} - -void WebAXObjectProxy::scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant* result) -{ - accessibilityObject().scrollToMakeVisible(); - result->setNull(); -} - -void WebAXObjectProxy::scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() != 4 - || !arguments[0].isNumber() - || !arguments[1].isNumber() - || !arguments[2].isNumber() - || !arguments[3].isNumber()) - return; - - int x = arguments[0].toInt32(); - int y = arguments[1].toInt32(); - int width = arguments[2].toInt32(); - int height = arguments[3].toInt32(); - accessibilityObject().scrollToMakeVisibleWithSubFocus(WebRect(x, y, width, height)); - result->setNull(); -} - -void WebAXObjectProxy::scrollToGlobalPointCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() != 2 - || !arguments[0].isNumber() - || !arguments[1].isNumber()) - return; - - int x = arguments[0].toInt32(); - int y = arguments[1].toInt32(); - - accessibilityObject().scrollToGlobalPoint(WebPoint(x, y)); - result->setNull(); -} - -void WebAXObjectProxy::wordStartCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() != 1 || !arguments[0].isNumber()) - return; - - if (accessibilityObject().role() != WebAXRoleStaticText) - return; - - int characterIndex = arguments[0].toInt32(); - int wordStart, wordEnd; - getBoundariesForOneWord(accessibilityObject(), characterIndex, wordStart, wordEnd); - result->set(wordStart); -} - -void WebAXObjectProxy::wordEndCallback(const CppArgumentList& arguments, CppVariant* result) -{ - result->setNull(); - - if (arguments.size() != 1 || !arguments[0].isNumber()) - return; - - if (accessibilityObject().role() != WebAXRoleStaticText) - return; - - int characterIndex = arguments[0].toInt32(); - int wordStart, wordEnd; - getBoundariesForOneWord(accessibilityObject(), characterIndex, wordStart, wordEnd); - result->set(wordEnd); -} - -void WebAXObjectProxy::fallbackCallback(const CppArgumentList &, CppVariant* result) -{ - result->setNull(); -} - -RootWebAXObjectProxy::RootWebAXObjectProxy(const WebAXObject &object, Factory *factory) - : WebAXObjectProxy(object, factory) { } - -WebAXObjectProxy* RootWebAXObjectProxy::getChildAtIndex(unsigned index) -{ - if (index) - return 0; - - return factory()->getOrCreate(accessibilityObject()); -} - -bool RootWebAXObjectProxy::isRoot() const -{ - return true; -} - -WebAXObjectProxyList::WebAXObjectProxyList() -{ -} - -WebAXObjectProxyList::~WebAXObjectProxyList() -{ - clear(); -} - -void WebAXObjectProxyList::clear() -{ - for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i) - delete (*i); - m_elements.clear(); -} - -WebAXObjectProxy* WebAXObjectProxyList::getOrCreate(const WebAXObject& object) -{ - if (object.isNull()) - return 0; - - size_t elementCount = m_elements.size(); - for (size_t i = 0; i < elementCount; i++) { - if (m_elements[i]->isEqual(object)) - return m_elements[i]; - } - - WebAXObjectProxy* element = new WebAXObjectProxy(object, this); - m_elements.push_back(element); - return element; -} - -WebAXObjectProxy* WebAXObjectProxyList::createRoot(const WebAXObject& object) -{ - WebAXObjectProxy* element = new RootWebAXObjectProxy(object, this); - m_elements.push_back(element); - return element; -} - -} diff --git a/content/shell/renderer/test_runner/WebAXObjectProxy.h b/content/shell/renderer/test_runner/WebAXObjectProxy.h deleted file mode 100644 index 59162f2..0000000 --- a/content/shell/renderer/test_runner/WebAXObjectProxy.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_WEBAXOBJECTPROXY_H_ -#define CONTENT_SHELL_RENDERER_TEST_RUNNER_WEBAXOBJECTPROXY_H_ - -#include <vector> - -#include "content/shell/renderer/test_runner/CppBoundClass.h" -#include "third_party/WebKit/public/web/WebAXObject.h" - -namespace WebTestRunner { - -class WebAXObjectProxy : public CppBoundClass { -public: - class Factory { - public: - virtual ~Factory() { } - virtual WebAXObjectProxy* getOrCreate(const blink::WebAXObject&) = 0; - }; - - WebAXObjectProxy(const blink::WebAXObject&, Factory*); - virtual ~WebAXObjectProxy(); - - virtual WebAXObjectProxy* getChildAtIndex(unsigned); - virtual bool isRoot() const; - virtual bool isEqual(const blink::WebAXObject&); - - virtual void notificationReceived(const char *notificationName); - -protected: - const blink::WebAXObject& accessibilityObject() const { return m_accessibilityObject; } - - Factory* factory() const { return m_factory; } - -private: - // Bound properties. - void roleGetterCallback(CppVariant*); - void titleGetterCallback(CppVariant*); - void descriptionGetterCallback(CppVariant*); - void helpTextGetterCallback(CppVariant*); - void stringValueGetterCallback(CppVariant*); - void xGetterCallback(CppVariant*); - void yGetterCallback(CppVariant*); - void widthGetterCallback(CppVariant*); - void heightGetterCallback(CppVariant*); - void intValueGetterCallback(CppVariant*); - void minValueGetterCallback(CppVariant*); - void maxValueGetterCallback(CppVariant*); - void valueDescriptionGetterCallback(CppVariant*); - void childrenCountGetterCallback(CppVariant*); - void insertionPointLineNumberGetterCallback(CppVariant*); - void selectedTextRangeGetterCallback(CppVariant*); - void isEnabledGetterCallback(CppVariant*); - void isRequiredGetterCallback(CppVariant*); - void isFocusedGetterCallback(CppVariant*); - void isFocusableGetterCallback(CppVariant*); - void isSelectedGetterCallback(CppVariant*); - void isSelectableGetterCallback(CppVariant*); - void isMultiSelectableGetterCallback(CppVariant*); - void isSelectedOptionActiveGetterCallback(CppVariant*); - void isExpandedGetterCallback(CppVariant*); - void isCheckedGetterCallback(CppVariant*); - void isVisibleGetterCallback(CppVariant*); - void isOffScreenGetterCallback(CppVariant*); - void isCollapsedGetterCallback(CppVariant*); - void hasPopupGetterCallback(CppVariant*); - void isValidGetterCallback(CppVariant*); - void isReadOnlyGetterCallback(CppVariant*); - void orientationGetterCallback(CppVariant*); - void clickPointXGetterCallback(CppVariant*); - void clickPointYGetterCallback(CppVariant*); - void rowCountGetterCallback(CppVariant*); - void columnCountGetterCallback(CppVariant*); - void isClickableGetterCallback(CppVariant*); - - // Bound methods. - void allAttributesCallback(const CppArgumentList&, CppVariant*); - void attributesOfChildrenCallback(const CppArgumentList&, CppVariant*); - void lineForIndexCallback(const CppArgumentList&, CppVariant*); - void boundsForRangeCallback(const CppArgumentList&, CppVariant*); - void childAtIndexCallback(const CppArgumentList&, CppVariant*); - void elementAtPointCallback(const CppArgumentList&, CppVariant*); - void tableHeaderCallback(const CppArgumentList&, CppVariant*); - void rowIndexRangeCallback(const CppArgumentList&, CppVariant*); - void columnIndexRangeCallback(const CppArgumentList&, CppVariant*); - void cellForColumnAndRowCallback(const CppArgumentList&, CppVariant*); - void titleUIElementCallback(const CppArgumentList&, CppVariant*); - void setSelectedTextRangeCallback(const CppArgumentList&, CppVariant*); - void isAttributeSettableCallback(const CppArgumentList&, CppVariant*); - void isPressActionSupportedCallback(const CppArgumentList&, CppVariant*); - void isIncrementActionSupportedCallback(const CppArgumentList&, CppVariant*); - void isDecrementActionSupportedCallback(const CppArgumentList&, CppVariant*); - void parentElementCallback(const CppArgumentList&, CppVariant*); - void incrementCallback(const CppArgumentList&, CppVariant*); - void decrementCallback(const CppArgumentList&, CppVariant*); - void showMenuCallback(const CppArgumentList&, CppVariant*); - void pressCallback(const CppArgumentList&, CppVariant*); - void isEqualCallback(const CppArgumentList&, CppVariant*); - void addNotificationListenerCallback(const CppArgumentList&, CppVariant*); - void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*); - void takeFocusCallback(const CppArgumentList&, CppVariant*); - void scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant*); - void scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList&, CppVariant*); - void scrollToGlobalPointCallback(const CppArgumentList&, CppVariant*); - void wordStartCallback(const CppArgumentList&, CppVariant*); - void wordEndCallback(const CppArgumentList&, CppVariant*); - - void fallbackCallback(const CppArgumentList&, CppVariant*); - - blink::WebAXObject m_accessibilityObject; - Factory* m_factory; - std::vector<CppVariant> m_notificationCallbacks; -}; - - -class RootWebAXObjectProxy : public WebAXObjectProxy { -public: - RootWebAXObjectProxy(const blink::WebAXObject&, Factory*); - - virtual WebAXObjectProxy* getChildAtIndex(unsigned) OVERRIDE; - virtual bool isRoot() const OVERRIDE; -}; - - -// Provides simple lifetime management of the WebAXObjectProxy instances: -// all WebAXObjectProxys ever created from the controller are stored in -// a list and cleared explicitly. -class WebAXObjectProxyList : public WebAXObjectProxy::Factory { -public: - WebAXObjectProxyList(); - virtual ~WebAXObjectProxyList(); - - void clear(); - virtual WebAXObjectProxy* getOrCreate(const blink::WebAXObject&) OVERRIDE; - WebAXObjectProxy* createRoot(const blink::WebAXObject&); - -private: - typedef std::vector<WebAXObjectProxy*> ElementList; - ElementList m_elements; -}; - -} - -#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_WEBAXOBJECTPROXY_H_ diff --git a/content/shell/renderer/test_runner/WebTestProxy.cpp b/content/shell/renderer/test_runner/WebTestProxy.cpp index 49e913c..2948c77 100644 --- a/content/shell/renderer/test_runner/WebTestProxy.cpp +++ b/content/shell/renderer/test_runner/WebTestProxy.cpp @@ -6,7 +6,6 @@ #include <cctype> -#include "content/shell/renderer/test_runner/AccessibilityController.h" #include "content/shell/renderer/test_runner/EventSender.h" #include "content/shell/renderer/test_runner/MockColorChooser.h" #include "content/shell/renderer/test_runner/MockWebSpeechInputController.h" @@ -20,6 +19,7 @@ #include "content/shell/renderer/test_runner/WebTestInterfaces.h" #include "content/shell/renderer/test_runner/WebTestRunner.h" #include "content/shell/renderer/test_runner/WebUserMediaClientMock.h" +#include "content/shell/renderer/test_runner/accessibility_controller.h" // FIXME: Including platform_canvas.h here is a layering violation. #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/public/platform/WebCString.h" @@ -759,7 +759,7 @@ void WebTestProxyBase::didAutoResize(const WebSize&) void WebTestProxyBase::postAccessibilityEvent(const blink::WebAXObject& obj, blink::WebAXEvent event) { if (event == blink::WebAXEventFocus) - m_testInterfaces->accessibilityController()->setFocusedElement(obj); + m_testInterfaces->accessibilityController()->SetFocusedElement(obj); const char* eventName = 0; switch (event) { @@ -849,9 +849,9 @@ void WebTestProxyBase::postAccessibilityEvent(const blink::WebAXObject& obj, bli break; } - m_testInterfaces->accessibilityController()->notificationReceived(obj, eventName); + m_testInterfaces->accessibilityController()->NotificationReceived(obj, eventName); - if (m_testInterfaces->accessibilityController()->shouldLogAccessibilityEvents()) { + if (m_testInterfaces->accessibilityController()->ShouldLogAccessibilityEvents()) { string message("AccessibilityNotification - "); message += eventName; diff --git a/content/shell/renderer/test_runner/accessibility_controller.cc b/content/shell/renderer/test_runner/accessibility_controller.cc new file mode 100644 index 0000000..79c6526 --- /dev/null +++ b/content/shell/renderer/test_runner/accessibility_controller.cc @@ -0,0 +1,272 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/renderer/test_runner/accessibility_controller.h" + +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "gin/wrappable.h" +#include "third_party/WebKit/public/web/WebElement.h" +#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebView.h" + +namespace content { + +class AccessibilityControllerBindings + : public gin::Wrappable<AccessibilityControllerBindings> { + public: + static gin::WrapperInfo kWrapperInfo; + + static void Install(base::WeakPtr<AccessibilityController> controller, + blink::WebFrame* frame); + + private: + explicit AccessibilityControllerBindings( + base::WeakPtr<AccessibilityController> controller); + virtual ~AccessibilityControllerBindings(); + + // gin::Wrappable: + virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; + + void LogAccessibilityEvents(); + void SetNotificationListener(v8::Handle<v8::Function> callback); + void UnsetNotificationListener(); + v8::Handle<v8::Object> FocusedElement(); + v8::Handle<v8::Object> RootElement(); + v8::Handle<v8::Object> AccessibleElementById(const std::string& id); + + base::WeakPtr<AccessibilityController> controller_; + + DISALLOW_COPY_AND_ASSIGN(AccessibilityControllerBindings); +}; + +gin::WrapperInfo AccessibilityControllerBindings::kWrapperInfo = { + gin::kEmbedderNativeGin}; + +// static +void AccessibilityControllerBindings::Install( + base::WeakPtr<AccessibilityController> controller, + blink::WebFrame* frame) { + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); + if (context.IsEmpty()) + return; + + v8::Context::Scope context_scope(context); + + gin::Handle<AccessibilityControllerBindings> bindings = + gin::CreateHandle(isolate, + new AccessibilityControllerBindings(controller)); + v8::Handle<v8::Object> global = context->Global(); + global->Set(gin::StringToV8(isolate, "accessibilityController"), + bindings.ToV8()); +} + +AccessibilityControllerBindings::AccessibilityControllerBindings( + base::WeakPtr<AccessibilityController> controller) + : controller_(controller) { +} + +AccessibilityControllerBindings::~AccessibilityControllerBindings() { +} + +gin::ObjectTemplateBuilder +AccessibilityControllerBindings::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return gin::Wrappable<AccessibilityControllerBindings>:: + GetObjectTemplateBuilder(isolate) + .SetMethod("logAccessibilityEvents", + &AccessibilityControllerBindings::LogAccessibilityEvents) + .SetMethod("setNotificationListener", + &AccessibilityControllerBindings::SetNotificationListener) + .SetMethod("unsetNotificationListener", + &AccessibilityControllerBindings::UnsetNotificationListener) + .SetProperty("focusedElement", + &AccessibilityControllerBindings::FocusedElement) + .SetProperty("rootElement", + &AccessibilityControllerBindings::RootElement) + .SetMethod("accessibleElementById", + &AccessibilityControllerBindings::AccessibleElementById) + // TODO(hajimehoshi): These are for backward compatibility. Remove them. + .SetMethod("addNotificationListener", + &AccessibilityControllerBindings::SetNotificationListener) + .SetMethod("removeNotificationListener", + &AccessibilityControllerBindings::UnsetNotificationListener); +} + +void AccessibilityControllerBindings::LogAccessibilityEvents() { + if (controller_) + controller_->LogAccessibilityEvents(); +} + +void AccessibilityControllerBindings::SetNotificationListener( + v8::Handle<v8::Function> callback) { + if (controller_) + controller_->SetNotificationListener(callback); +} + +void AccessibilityControllerBindings::UnsetNotificationListener() { + if (controller_) + controller_->UnsetNotificationListener(); +} + +v8::Handle<v8::Object> AccessibilityControllerBindings::FocusedElement() { + return controller_ ? controller_->FocusedElement() : v8::Handle<v8::Object>(); +} + +v8::Handle<v8::Object> AccessibilityControllerBindings::RootElement() { + return controller_ ? controller_->RootElement() : v8::Handle<v8::Object>(); +} + +v8::Handle<v8::Object> AccessibilityControllerBindings::AccessibleElementById( + const std::string& id) { + return controller_ ? controller_->AccessibleElementById(id) + : v8::Handle<v8::Object>(); +} + +AccessibilityController::AccessibilityController() + : log_accessibility_events_(false), + weak_factory_(this) { +} + +AccessibilityController::~AccessibilityController() {} + +void AccessibilityController::Reset() { + root_element_ = blink::WebAXObject(); + focused_element_ = blink::WebAXObject(); + elements_.Clear(); + notification_callback_.Reset(); + log_accessibility_events_ = false; +} + +void AccessibilityController::Install(blink::WebFrame* frame) { + blink::WebAXObject::enableAccessibility(); + blink::WebAXObject::enableInlineTextBoxAccessibility(); + AccessibilityControllerBindings::Install(weak_factory_.GetWeakPtr(), frame); +} + +void AccessibilityController::SetFocusedElement( + const blink::WebAXObject& focused_element) { + focused_element_ = focused_element; +} + +bool AccessibilityController::ShouldLogAccessibilityEvents() { + return log_accessibility_events_; +} + +void AccessibilityController::NotificationReceived( + const blink::WebAXObject& target, const std::string& notification_name) { + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + + blink::WebFrame* frame = web_view_->mainFrame(); + if (!frame) + return; + + v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); + if (context.IsEmpty()) + return; + + v8::Context::Scope context_scope(context); + + // Call notification listeners on the element. + v8::Handle<v8::Object> element_handle = elements_.GetOrCreate(target); + WebAXObjectProxy* element; + bool result = gin::ConvertFromV8(isolate, element_handle, &element); + DCHECK(result); + element->NotificationReceived(frame, notification_name); + + if (notification_callback_.IsEmpty()) + return; + + // Call global notification listeners. + v8::Handle<v8::Value> argv[] = { + element_handle, + v8::String::NewFromUtf8(isolate, notification_name.data(), + v8::String::kNormalString, + notification_name.size()), + }; + frame->callFunctionEvenIfScriptDisabled( + v8::Local<v8::Function>::New(isolate, notification_callback_), + context->Global(), + arraysize(argv), + argv); +} + +void AccessibilityController::SetDelegate( + WebTestRunner::WebTestDelegate* delegate) { + delegate_ = delegate; +} + +void AccessibilityController::SetWebView(blink::WebView* web_view) { + web_view_ = web_view; +} + +void AccessibilityController::LogAccessibilityEvents() { + log_accessibility_events_ = true; +} + +void AccessibilityController::SetNotificationListener( + v8::Handle<v8::Function> callback) { + v8::Isolate* isolate = blink::mainThreadIsolate(); + notification_callback_.Reset(isolate, callback); +} + +void AccessibilityController::UnsetNotificationListener() { + notification_callback_.Reset(); +} + +v8::Handle<v8::Object> AccessibilityController::FocusedElement() { + if (focused_element_.isNull()) + focused_element_ = web_view_->accessibilityObject(); + return elements_.GetOrCreate(focused_element_); +} + +v8::Handle<v8::Object> AccessibilityController::RootElement() { + if (root_element_.isNull()) + root_element_ = web_view_->accessibilityObject(); + return elements_.CreateRoot(root_element_); +} + +v8::Handle<v8::Object> +AccessibilityController::AccessibleElementById(const std::string& id) { + if (root_element_.isNull()) + root_element_ = web_view_->accessibilityObject(); + + if (!root_element_.updateBackingStoreAndCheckValidity()) + return v8::Handle<v8::Object>(); + + return FindAccessibleElementByIdRecursive( + root_element_, blink::WebString::fromUTF8(id.c_str())); +} + +v8::Handle<v8::Object> +AccessibilityController::FindAccessibleElementByIdRecursive( + const blink::WebAXObject& obj, const blink::WebString& id) { + if (obj.isNull() || obj.isDetached()) + return v8::Handle<v8::Object>(); + + blink::WebNode node = obj.node(); + if (!node.isNull() && node.isElementNode()) { + blink::WebElement element = node.to<blink::WebElement>(); + element.getAttribute("id"); + if (element.getAttribute("id") == id) + return elements_.GetOrCreate(obj); + } + + unsigned childCount = obj.childCount(); + for (unsigned i = 0; i < childCount; i++) { + v8::Handle<v8::Object> result = + FindAccessibleElementByIdRecursive(obj.childAt(i), id); + if (*result) + return result; + } + + return v8::Handle<v8::Object>(); +} + +} // namespace content diff --git a/content/shell/renderer/test_runner/accessibility_controller.h b/content/shell/renderer/test_runner/accessibility_controller.h new file mode 100644 index 0000000..30e0131 --- /dev/null +++ b/content/shell/renderer/test_runner/accessibility_controller.h @@ -0,0 +1,77 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_ACCESSIBILITY_CONTROLLER_H_ +#define CONTENT_SHELL_RENDERER_TEST_RUNNER_ACCESSIBILITY_CONTROLLER_H_ + +#include <vector> + +#include "base/memory/weak_ptr.h" +#include "content/shell/renderer/test_runner/web_ax_object_proxy.h" +#include "third_party/WebKit/public/web/WebAXObject.h" +#include "v8/include/v8.h" + +namespace blink { +class WebFrame; +class WebString; +class WebView; +} + +namespace WebTestRunner { +class WebTestDelegate; +} + +namespace content { + +class AccessibilityController : + public base::SupportsWeakPtr<AccessibilityController> { + public: + AccessibilityController(); + ~AccessibilityController(); + + void Reset(); + void Install(blink::WebFrame* frame); + void SetFocusedElement(const blink::WebAXObject&); + bool ShouldLogAccessibilityEvents(); + void NotificationReceived(const blink::WebAXObject& target, + const std::string& notification_name); + + void SetDelegate(WebTestRunner::WebTestDelegate* delegate); + void SetWebView(blink::WebView* web_view); + + private: + friend class AccessibilityControllerBindings; + + // Bound methods and properties + void LogAccessibilityEvents(); + void SetNotificationListener(v8::Handle<v8::Function> callback); + void UnsetNotificationListener(); + v8::Handle<v8::Object> FocusedElement(); + v8::Handle<v8::Object> RootElement(); + v8::Handle<v8::Object> AccessibleElementById(const std::string& id); + + v8::Handle<v8::Object> FindAccessibleElementByIdRecursive( + const blink::WebAXObject&, const blink::WebString& id); + + // If true, will log all accessibility notifications. + bool log_accessibility_events_; + + blink::WebAXObject focused_element_; + blink::WebAXObject root_element_; + + WebAXObjectProxyList elements_; + + v8::Persistent<v8::Function> notification_callback_; + + WebTestRunner::WebTestDelegate* delegate_; + blink::WebView* web_view_; + + base::WeakPtrFactory<AccessibilityController> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AccessibilityController); +}; + +} // namespace content + +#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_ACCESSIBILITY_CONTROLLER_H_ diff --git a/content/shell/renderer/test_runner/unsafe_persistent.h b/content/shell/renderer/test_runner/unsafe_persistent.h new file mode 100644 index 0000000..b47a33e --- /dev/null +++ b/content/shell/renderer/test_runner/unsafe_persistent.h @@ -0,0 +1,50 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_UNSAFE_PERSISTENT_H_ +#define CONTENT_SHELL_RENDERER_TEST_RUNNER_UNSAFE_PERSISTENT_H_ + +#include "v8/include/v8.h" + +namespace content { + +// An unsafe way to pass Persistent handles around. Do not use unless you know +// what you're doing. UnsafePersistent is only safe to use when we know that the +// memory pointed by it is not going away: 1) When GC cannot happen while the +// UnsafePersistent is alive or 2) when there is a strong Persistent keeping the +// memory alive while the UnsafePersistent is alive. +template<typename T> class UnsafePersistent { + public: + UnsafePersistent() : value_(0) { } + + explicit UnsafePersistent(v8::Persistent<T>* handle) { + value_ = handle->ClearAndLeak(); + } + + UnsafePersistent(v8::Isolate* isolate, const v8::Handle<T>& handle) { + v8::Persistent<T> persistent(isolate, handle); + value_ = persistent.ClearAndLeak(); + } + + // Usage of this function requires + // V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR to be defined + void Dispose() { + v8::Persistent<T> handle(value_); + handle.Reset(); + value_ = 0; + } + + // Usage of this function requires + // V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR to be defined + v8::Local<T> NewLocal(v8::Isolate* isolate) { + return v8::Local<T>::New(isolate, v8::Local<T>(value_)); + } + + private: + T* value_; +}; + +} // namespace content + +#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_UNSAFE_PERSISTENT_H_ diff --git a/content/shell/renderer/test_runner/web_ax_object_proxy.cc b/content/shell/renderer/test_runner/web_ax_object_proxy.cc new file mode 100644 index 0000000..7d6f186 --- /dev/null +++ b/content/shell/renderer/test_runner/web_ax_object_proxy.cc @@ -0,0 +1,1024 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TODO(hajimehoshi): Remove this when UnsafePersistent is removed. +#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR + +#include "content/shell/renderer/test_runner/web_ax_object_proxy.h" + +#include "base/strings/stringprintf.h" +#include "gin/handle.h" +#include "third_party/WebKit/public/platform/WebPoint.h" +#include "third_party/WebKit/public/platform/WebRect.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebKit.h" + +namespace content { + +namespace { + +// Map role value to string, matching Safari/Mac platform implementation to +// avoid rebaselining layout tests. +std::string RoleToString(blink::WebAXRole role) +{ + std::string result = "AXRole: AX"; + switch (role) { + case blink::WebAXRoleAlertDialog: + return result.append("AlertDialog"); + case blink::WebAXRoleAlert: + return result.append("Alert"); + case blink::WebAXRoleAnnotation: + return result.append("Annotation"); + case blink::WebAXRoleApplication: + return result.append("Application"); + case blink::WebAXRoleArticle: + return result.append("Article"); + case blink::WebAXRoleBanner: + return result.append("Banner"); + case blink::WebAXRoleBrowser: + return result.append("Browser"); + case blink::WebAXRoleBusyIndicator: + return result.append("BusyIndicator"); + case blink::WebAXRoleButton: + return result.append("Button"); + case blink::WebAXRoleCanvas: + return result.append("Canvas"); + case blink::WebAXRoleCell: + return result.append("Cell"); + case blink::WebAXRoleCheckBox: + return result.append("CheckBox"); + case blink::WebAXRoleColorWell: + return result.append("ColorWell"); + case blink::WebAXRoleColumnHeader: + return result.append("ColumnHeader"); + case blink::WebAXRoleColumn: + return result.append("Column"); + case blink::WebAXRoleComboBox: + return result.append("ComboBox"); + case blink::WebAXRoleComplementary: + return result.append("Complementary"); + case blink::WebAXRoleContentInfo: + return result.append("ContentInfo"); + case blink::WebAXRoleDefinition: + return result.append("Definition"); + case blink::WebAXRoleDescriptionListDetail: + return result.append("DescriptionListDetail"); + case blink::WebAXRoleDescriptionListTerm: + return result.append("DescriptionListTerm"); + case blink::WebAXRoleDialog: + return result.append("Dialog"); + case blink::WebAXRoleDirectory: + return result.append("Directory"); + case blink::WebAXRoleDisclosureTriangle: + return result.append("DisclosureTriangle"); + case blink::WebAXRoleDiv: + return result.append("Div"); + case blink::WebAXRoleDocument: + return result.append("Document"); + case blink::WebAXRoleDrawer: + return result.append("Drawer"); + case blink::WebAXRoleEditableText: + return result.append("EditableText"); + case blink::WebAXRoleFooter: + return result.append("Footer"); + case blink::WebAXRoleForm: + return result.append("Form"); + case blink::WebAXRoleGrid: + return result.append("Grid"); + case blink::WebAXRoleGroup: + return result.append("Group"); + case blink::WebAXRoleGrowArea: + return result.append("GrowArea"); + case blink::WebAXRoleHeading: + return result.append("Heading"); + case blink::WebAXRoleHelpTag: + return result.append("HelpTag"); + case blink::WebAXRoleHorizontalRule: + return result.append("HorizontalRule"); + case blink::WebAXRoleIgnored: + return result.append("Ignored"); + case blink::WebAXRoleImageMapLink: + return result.append("ImageMapLink"); + case blink::WebAXRoleImageMap: + return result.append("ImageMap"); + case blink::WebAXRoleImage: + return result.append("Image"); + case blink::WebAXRoleIncrementor: + return result.append("Incrementor"); + case blink::WebAXRoleInlineTextBox: + return result.append("InlineTextBox"); + case blink::WebAXRoleLabel: + return result.append("Label"); + case blink::WebAXRoleLegend: + return result.append("Legend"); + case blink::WebAXRoleLink: + return result.append("Link"); + case blink::WebAXRoleListBoxOption: + return result.append("ListBoxOption"); + case blink::WebAXRoleListBox: + return result.append("ListBox"); + case blink::WebAXRoleListItem: + return result.append("ListItem"); + case blink::WebAXRoleListMarker: + return result.append("ListMarker"); + case blink::WebAXRoleList: + return result.append("List"); + case blink::WebAXRoleLog: + return result.append("Log"); + case blink::WebAXRoleMain: + return result.append("Main"); + case blink::WebAXRoleMarquee: + return result.append("Marquee"); + case blink::WebAXRoleMathElement: + return result.append("MathElement"); + case blink::WebAXRoleMath: + return result.append("Math"); + case blink::WebAXRoleMatte: + return result.append("Matte"); + case blink::WebAXRoleMenuBar: + return result.append("MenuBar"); + case blink::WebAXRoleMenuButton: + return result.append("MenuButton"); + case blink::WebAXRoleMenuItem: + return result.append("MenuItem"); + case blink::WebAXRoleMenuListOption: + return result.append("MenuListOption"); + case blink::WebAXRoleMenuListPopup: + return result.append("MenuListPopup"); + case blink::WebAXRoleMenu: + return result.append("Menu"); + case blink::WebAXRoleNavigation: + return result.append("Navigation"); + case blink::WebAXRoleNote: + return result.append("Note"); + case blink::WebAXRoleOutline: + return result.append("Outline"); + case blink::WebAXRoleParagraph: + return result.append("Paragraph"); + case blink::WebAXRolePopUpButton: + return result.append("PopUpButton"); + case blink::WebAXRolePresentational: + return result.append("Presentational"); + case blink::WebAXRoleProgressIndicator: + return result.append("ProgressIndicator"); + case blink::WebAXRoleRadioButton: + return result.append("RadioButton"); + case blink::WebAXRoleRadioGroup: + return result.append("RadioGroup"); + case blink::WebAXRoleRegion: + return result.append("Region"); + case blink::WebAXRoleRootWebArea: + return result.append("RootWebArea"); + case blink::WebAXRoleRowHeader: + return result.append("RowHeader"); + case blink::WebAXRoleRow: + return result.append("Row"); + case blink::WebAXRoleRulerMarker: + return result.append("RulerMarker"); + case blink::WebAXRoleRuler: + return result.append("Ruler"); + case blink::WebAXRoleSVGRoot: + return result.append("SVGRoot"); + case blink::WebAXRoleScrollArea: + return result.append("ScrollArea"); + case blink::WebAXRoleScrollBar: + return result.append("ScrollBar"); + case blink::WebAXRoleSeamlessWebArea: + return result.append("SeamlessWebArea"); + case blink::WebAXRoleSearch: + return result.append("Search"); + case blink::WebAXRoleSheet: + return result.append("Sheet"); + case blink::WebAXRoleSlider: + return result.append("Slider"); + case blink::WebAXRoleSliderThumb: + return result.append("SliderThumb"); + case blink::WebAXRoleSpinButtonPart: + return result.append("SpinButtonPart"); + case blink::WebAXRoleSpinButton: + return result.append("SpinButton"); + case blink::WebAXRoleSplitGroup: + return result.append("SplitGroup"); + case blink::WebAXRoleSplitter: + return result.append("Splitter"); + case blink::WebAXRoleStaticText: + return result.append("StaticText"); + case blink::WebAXRoleStatus: + return result.append("Status"); + case blink::WebAXRoleSystemWide: + return result.append("SystemWide"); + case blink::WebAXRoleTabGroup: + return result.append("TabGroup"); + case blink::WebAXRoleTabList: + return result.append("TabList"); + case blink::WebAXRoleTabPanel: + return result.append("TabPanel"); + case blink::WebAXRoleTab: + return result.append("Tab"); + case blink::WebAXRoleTableHeaderContainer: + return result.append("TableHeaderContainer"); + case blink::WebAXRoleTable: + return result.append("Table"); + case blink::WebAXRoleTextArea: + return result.append("TextArea"); + case blink::WebAXRoleTextField: + return result.append("TextField"); + case blink::WebAXRoleTimer: + return result.append("Timer"); + case blink::WebAXRoleToggleButton: + return result.append("ToggleButton"); + case blink::WebAXRoleToolbar: + return result.append("Toolbar"); + case blink::WebAXRoleTreeGrid: + return result.append("TreeGrid"); + case blink::WebAXRoleTreeItem: + return result.append("TreeItem"); + case blink::WebAXRoleTree: + return result.append("Tree"); + case blink::WebAXRoleUnknown: + return result.append("Unknown"); + case blink::WebAXRoleUserInterfaceTooltip: + return result.append("UserInterfaceTooltip"); + case blink::WebAXRoleValueIndicator: + return result.append("ValueIndicator"); + case blink::WebAXRoleWebArea: + return result.append("WebArea"); + case blink::WebAXRoleWindow: + return result.append("Window"); + default: + return result.append("Unknown"); + } +} + +std::string GetDescription(const blink::WebAXObject& object) { + std::string description = object.accessibilityDescription().utf8(); + return description.insert(0, "AXDescription: "); +} + +std::string GetHelpText(const blink::WebAXObject& object) { + std::string help_text = object.helpText().utf8(); + return help_text.insert(0, "AXHelp: "); +} + +std::string GetStringValue(const blink::WebAXObject& object) { + std::string value; + if (object.role() == blink::WebAXRoleColorWell) { + int r, g, b; + object.colorValue(r, g, b); + value = base::StringPrintf("rgb %7.5f %7.5f %7.5f 1", + r / 255., g / 255., b / 255.); + } else { + value = object.stringValue().utf8(); + } + return value.insert(0, "AXValue: "); +} + +std::string GetRole(const blink::WebAXObject& object) { + std::string role_string = RoleToString(object.role()); + + // Special-case canvas with fallback content because Chromium wants to treat + // this as essentially a separate role that it can map differently depending + // on the platform. + if (object.role() == blink::WebAXRoleCanvas && + object.canvasHasFallbackContent()) { + role_string += "WithFallbackContent"; + } + + return role_string; +} + +std::string GetTitle(const blink::WebAXObject& object) { + std::string title = object.title().utf8(); + return title.insert(0, "AXTitle: "); +} + +std::string GetOrientation(const blink::WebAXObject& object) { + if (object.isVertical()) + return "AXOrientation: AXVerticalOrientation"; + + return "AXOrientation: AXHorizontalOrientation"; +} + +std::string GetValueDescription(const blink::WebAXObject& object) { + std::string value_description = object.valueDescription().utf8(); + return value_description.insert(0, "AXValueDescription: "); +} + +std::string GetAttributes(const blink::WebAXObject& object) { + // FIXME: Concatenate all attributes of the AXObject. + std::string attributes(GetTitle(object)); + attributes.append("\n"); + attributes.append(GetRole(object)); + attributes.append("\n"); + attributes.append(GetDescription(object)); + return attributes; +} + +blink::WebRect BoundsForCharacter(const blink::WebAXObject& object, + int characterIndex) { + DCHECK_EQ(object.role(), blink::WebAXRoleStaticText); + int end = 0; + for (unsigned i = 0; i < object.childCount(); i++) { + blink::WebAXObject inline_text_box = object.childAt(i); + DCHECK_EQ(inline_text_box.role(), blink::WebAXRoleInlineTextBox); + int start = end; + end += inline_text_box.stringValue().length(); + if (end <= characterIndex) + continue; + blink::WebRect inline_text_box_rect = inline_text_box.boundingBoxRect(); + int localIndex = characterIndex - start; + blink::WebVector<int> character_offsets; + inline_text_box.characterOffsets(character_offsets); + DCHECK(character_offsets.size() > 0 && + character_offsets.size() == inline_text_box.stringValue().length()); + switch (inline_text_box.textDirection()) { + case blink::WebAXTextDirectionLR: { + if (localIndex) { + int left = inline_text_box_rect.x + character_offsets[localIndex - 1]; + int width = character_offsets[localIndex] - + character_offsets[localIndex - 1]; + return blink::WebRect(left, inline_text_box_rect.y, + width, inline_text_box_rect.height); + } + return blink::WebRect( + inline_text_box_rect.x, inline_text_box_rect.y, + character_offsets[0], inline_text_box_rect.height); + } + case blink::WebAXTextDirectionRL: { + int right = inline_text_box_rect.x + inline_text_box_rect.width; + + if (localIndex) { + int left = right - character_offsets[localIndex]; + int width = character_offsets[localIndex] - + character_offsets[localIndex - 1]; + return blink::WebRect(left, inline_text_box_rect.y, + width, inline_text_box_rect.height); + } + int left = right - character_offsets[0]; + return blink::WebRect( + left, inline_text_box_rect.y, + character_offsets[0], inline_text_box_rect.height); + } + case blink::WebAXTextDirectionTB: { + if (localIndex) { + int top = inline_text_box_rect.y + character_offsets[localIndex - 1]; + int height = character_offsets[localIndex] - + character_offsets[localIndex - 1]; + return blink::WebRect(inline_text_box_rect.x, top, + inline_text_box_rect.width, height); + } + return blink::WebRect(inline_text_box_rect.x, inline_text_box_rect.y, + inline_text_box_rect.width, character_offsets[0]); + } + case blink::WebAXTextDirectionBT: { + int bottom = inline_text_box_rect.y + inline_text_box_rect.height; + + if (localIndex) { + int top = bottom - character_offsets[localIndex]; + int height = character_offsets[localIndex] - + character_offsets[localIndex - 1]; + return blink::WebRect(inline_text_box_rect.x, top, + inline_text_box_rect.width, height); + } + int top = bottom - character_offsets[0]; + return blink::WebRect(inline_text_box_rect.x, top, + inline_text_box_rect.width, character_offsets[0]); + } + } + } + + DCHECK(false); + return blink::WebRect(); +} + +void GetBoundariesForOneWord(const blink::WebAXObject& object, + int character_index, + int& word_start, + int& word_end) { + int end = 0; + for (unsigned i = 0; i < object.childCount(); i++) { + blink::WebAXObject inline_text_box = object.childAt(i); + DCHECK_EQ(inline_text_box.role(), blink::WebAXRoleInlineTextBox); + int start = end; + end += inline_text_box.stringValue().length(); + if (end <= character_index) + continue; + int localIndex = character_index - start; + + blink::WebVector<int> starts; + blink::WebVector<int> ends; + inline_text_box.wordBoundaries(starts, ends); + size_t word_count = starts.size(); + DCHECK_EQ(ends.size(), word_count); + + // If there are no words, use the InlineTextBox boundaries. + if (!word_count) { + word_start = start; + word_end = end; + return; + } + + // Look for a character within any word other than the last. + for (size_t j = 0; j < word_count - 1; j++) { + if (localIndex <= ends[j]) { + word_start = start + starts[j]; + word_end = start + ends[j]; + return; + } + } + + // Return the last word by default. + word_start = start + starts[word_count - 1]; + word_end = start + ends[word_count - 1]; + return; + } +} + +// Collects attributes into a string, delimited by dashes. Used by all methods +// that output lists of attributes: attributesOfLinkedUIElementsCallback, +// AttributesOfChildrenCallback, etc. +class AttributesCollector { + public: + AttributesCollector() {} + ~AttributesCollector() {} + + void CollectAttributes(const blink::WebAXObject& object) { + attributes_.append("\n------------\n"); + attributes_.append(GetAttributes(object)); + } + + std::string attributes() const { return attributes_; } + + private: + std::string attributes_; + + DISALLOW_COPY_AND_ASSIGN(AttributesCollector); +}; + +} // namespace + +gin::WrapperInfo WebAXObjectProxy::kWrapperInfo = { + gin::kEmbedderNativeGin}; + +WebAXObjectProxy::WebAXObjectProxy(const blink::WebAXObject& object, + WebAXObjectProxy::Factory* factory) + : accessibility_object_(object), + factory_(factory) { +} + +WebAXObjectProxy::~WebAXObjectProxy() {} + +gin::ObjectTemplateBuilder +WebAXObjectProxy::GetObjectTemplateBuilder(v8::Isolate* isolate) { + return gin::Wrappable<WebAXObjectProxy>::GetObjectTemplateBuilder(isolate) + .SetProperty("role", &WebAXObjectProxy::Role) + .SetProperty("title", &WebAXObjectProxy::Title) + .SetProperty("description", &WebAXObjectProxy::Description) + .SetProperty("helpText", &WebAXObjectProxy::HelpText) + .SetProperty("stringValue", &WebAXObjectProxy::StringValue) + .SetProperty("x", &WebAXObjectProxy::X) + .SetProperty("y", &WebAXObjectProxy::Y) + .SetProperty("width", &WebAXObjectProxy::Width) + .SetProperty("height", &WebAXObjectProxy::Height) + .SetProperty("intValue", &WebAXObjectProxy::IntValue) + .SetProperty("minValue", &WebAXObjectProxy::MinValue) + .SetProperty("maxValue", &WebAXObjectProxy::MaxValue) + .SetProperty("valueDescription", &WebAXObjectProxy::ValueDescription) + .SetProperty("childrenCount", &WebAXObjectProxy::ChildrenCount) + .SetProperty("insertionPointLineNumber", + &WebAXObjectProxy::InsertionPointLineNumber) + .SetProperty("selectedTextRange", &WebAXObjectProxy::SelectedTextRange) + .SetProperty("isEnabled", &WebAXObjectProxy::IsEnabled) + .SetProperty("isRequired", &WebAXObjectProxy::IsRequired) + .SetProperty("isFocused", &WebAXObjectProxy::IsFocused) + .SetProperty("isFocusable", &WebAXObjectProxy::IsFocusable) + .SetProperty("isSelected", &WebAXObjectProxy::IsSelected) + .SetProperty("isSelectable", &WebAXObjectProxy::IsSelectable) + .SetProperty("isMultiSelectable", &WebAXObjectProxy::IsMultiSelectable) + .SetProperty("isSelectedOptionActive", + &WebAXObjectProxy::IsSelectedOptionActive) + .SetProperty("isExpanded", &WebAXObjectProxy::IsExpanded) + .SetProperty("isChecked", &WebAXObjectProxy::IsChecked) + .SetProperty("isVisible", &WebAXObjectProxy::IsVisible) + .SetProperty("isOffScreen", &WebAXObjectProxy::IsOffScreen) + .SetProperty("isCollapsed", &WebAXObjectProxy::IsCollapsed) + .SetProperty("hasPopup", &WebAXObjectProxy::HasPopup) + .SetProperty("isValid", &WebAXObjectProxy::IsValid) + .SetProperty("isReadOnly", &WebAXObjectProxy::IsReadOnly) + .SetProperty("orientation", &WebAXObjectProxy::Orientation) + .SetProperty("clickPointX", &WebAXObjectProxy::ClickPointX) + .SetProperty("clickPointY", &WebAXObjectProxy::ClickPointY) + .SetProperty("rowCount", &WebAXObjectProxy::RowCount) + .SetProperty("columnCount", &WebAXObjectProxy::ColumnCount) + .SetProperty("isClickable", &WebAXObjectProxy::IsClickable) + .SetMethod("allAttributes", &WebAXObjectProxy::AllAttributes) + .SetMethod("attributesOfChildren", + &WebAXObjectProxy::AttributesOfChildren) + .SetMethod("lineForIndex", &WebAXObjectProxy::LineForIndex) + .SetMethod("boundsForRange", &WebAXObjectProxy::BoundsForRange) + .SetMethod("childAtIndex", &WebAXObjectProxy::ChildAtIndex) + .SetMethod("elementAtPoint", &WebAXObjectProxy::ElementAtPoint) + .SetMethod("tableHeader", &WebAXObjectProxy::TableHeader) + .SetMethod("rowIndexRange", &WebAXObjectProxy::RowIndexRange) + .SetMethod("columnIndexRange", &WebAXObjectProxy::ColumnIndexRange) + .SetMethod("cellForColumnAndRow", &WebAXObjectProxy::CellForColumnAndRow) + .SetMethod("titleUIElement", &WebAXObjectProxy::TitleUIElement) + .SetMethod("setSelectedTextRange", + &WebAXObjectProxy::SetSelectedTextRange) + .SetMethod("isAttributeSettable", &WebAXObjectProxy::IsAttributeSettable) + .SetMethod("isPressActionSupported", + &WebAXObjectProxy::IsPressActionSupported) + .SetMethod("isIncrementActionSupported", + &WebAXObjectProxy::IsIncrementActionSupported) + .SetMethod("isDecrementActionSupported", + &WebAXObjectProxy::IsDecrementActionSupported) + .SetMethod("parentElement", &WebAXObjectProxy::ParentElement) + .SetMethod("increment", &WebAXObjectProxy::Increment) + .SetMethod("decrement", &WebAXObjectProxy::Decrement) + .SetMethod("showMenu", &WebAXObjectProxy::ShowMenu) + .SetMethod("press", &WebAXObjectProxy::Press) + .SetMethod("isEqual", &WebAXObjectProxy::IsEqual) + .SetMethod("setNotificationListener", + &WebAXObjectProxy::SetNotificationListener) + .SetMethod("unsetNotificationListener", + &WebAXObjectProxy::UnsetNotificationListener) + .SetMethod("takeFocus", &WebAXObjectProxy::TakeFocus) + .SetMethod("scrollToMakeVisible", &WebAXObjectProxy::ScrollToMakeVisible) + .SetMethod("scrollToMakeVisibleWithSubFocus", + &WebAXObjectProxy::ScrollToMakeVisibleWithSubFocus) + .SetMethod("scrollToGlobalPoint", &WebAXObjectProxy::ScrollToGlobalPoint) + .SetMethod("wordStart", &WebAXObjectProxy::WordStart) + .SetMethod("wordEnd", &WebAXObjectProxy::WordEnd) + // TODO(hajimehoshi): This is for backward compatibility. Remove them. + .SetMethod("addNotificationListener", + &WebAXObjectProxy::SetNotificationListener) + .SetMethod("removeNotificationListener", + &WebAXObjectProxy::UnsetNotificationListener); +} + +v8::Handle<v8::Object> WebAXObjectProxy::GetChildAtIndex(unsigned index) { + return factory_->GetOrCreate(accessibility_object().childAt(index)); +} + +bool WebAXObjectProxy::IsRoot() const { + return false; +} + +bool WebAXObjectProxy::IsEqualToObject(const blink::WebAXObject& other) { + return accessibility_object().equals(other); +} + +void WebAXObjectProxy::NotificationReceived( + blink::WebFrame* frame, + const std::string& notification_name) { + if (notification_callback_.IsEmpty()) + return; + + v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); + if (context.IsEmpty()) + return; + + v8::Isolate* isolate = blink::mainThreadIsolate(); + + v8::Handle<v8::Value> argv[] = { + v8::String::NewFromUtf8(isolate, notification_name.data(), + v8::String::kNormalString, + notification_name.size()), + }; + frame->callFunctionEvenIfScriptDisabled( + v8::Local<v8::Function>::New(isolate, notification_callback_), + context->Global(), + arraysize(argv), + argv); +} + +std::string WebAXObjectProxy::Role() { + return GetRole(accessibility_object()); +} + +std::string WebAXObjectProxy::Title() { + return GetTitle(accessibility_object()); +} + +std::string WebAXObjectProxy::Description() { + return GetDescription(accessibility_object()); +} + +std::string WebAXObjectProxy::HelpText() { + return GetHelpText(accessibility_object()); +} + +std::string WebAXObjectProxy::StringValue() { + return GetStringValue(accessibility_object()); +} + +int WebAXObjectProxy::X() { + return accessibility_object().boundingBoxRect().x; +} + +int WebAXObjectProxy::Y() { + return accessibility_object().boundingBoxRect().y; +} + +int WebAXObjectProxy::Width() { + return accessibility_object().boundingBoxRect().width; +} + +int WebAXObjectProxy::Height() { + return accessibility_object().boundingBoxRect().height; +} + +int WebAXObjectProxy::IntValue() { + if (accessibility_object().supportsRangeValue()) + return accessibility_object().valueForRange(); + else if (accessibility_object().role() == blink::WebAXRoleHeading) + return accessibility_object().headingLevel(); + else + return atoi(accessibility_object().stringValue().utf8().data()); +} + +int WebAXObjectProxy::MinValue() { + return accessibility_object().minValueForRange(); +} + +int WebAXObjectProxy::MaxValue() { + return accessibility_object().maxValueForRange(); +} + +std::string WebAXObjectProxy::ValueDescription() { + return GetValueDescription(accessibility_object()); +} + +int WebAXObjectProxy::ChildrenCount() { + int count = 1; // Root object always has only one child, the WebView. + if (!IsRoot()) + count = accessibility_object().childCount(); + return count; +} + +int WebAXObjectProxy::InsertionPointLineNumber() { + if (!accessibility_object().isFocused()) + return -1; + return accessibility_object().selectionEndLineNumber(); +} + +std::string WebAXObjectProxy::SelectedTextRange() { + unsigned selection_start = accessibility_object().selectionStart(); + unsigned selection_end = accessibility_object().selectionEnd(); + return base::StringPrintf("{%d, %d}", + selection_start, selection_end - selection_start); +} + +bool WebAXObjectProxy::IsEnabled() { + return accessibility_object().isEnabled(); +} + +bool WebAXObjectProxy::IsRequired() { + return accessibility_object().isRequired(); +} + +bool WebAXObjectProxy::IsFocused() { + return accessibility_object().isFocused(); +} + +bool WebAXObjectProxy::IsFocusable() { + return accessibility_object().canSetFocusAttribute(); +} + +bool WebAXObjectProxy::IsSelected() { + return accessibility_object().isSelected(); +} + +bool WebAXObjectProxy::IsSelectable() { + return accessibility_object().canSetSelectedAttribute(); +} + +bool WebAXObjectProxy::IsMultiSelectable() { + return accessibility_object().isMultiSelectable(); +} + +bool WebAXObjectProxy::IsSelectedOptionActive() { + return accessibility_object().isSelectedOptionActive(); +} + +bool WebAXObjectProxy::IsExpanded() { + return !accessibility_object().isCollapsed(); +} + +bool WebAXObjectProxy::IsChecked() { + return accessibility_object().isChecked(); +} + +bool WebAXObjectProxy::IsVisible() { + return accessibility_object().isVisible(); +} + +bool WebAXObjectProxy::IsOffScreen() { + return accessibility_object().isOffScreen(); +} + +bool WebAXObjectProxy::IsCollapsed() { + return accessibility_object().isCollapsed(); +} + +bool WebAXObjectProxy::HasPopup() { + return accessibility_object().ariaHasPopup(); +} + +bool WebAXObjectProxy::IsValid() { + return !accessibility_object().isDetached(); +} + +bool WebAXObjectProxy::IsReadOnly() { + return accessibility_object().isReadOnly(); +} + +std::string WebAXObjectProxy::Orientation() { + return GetOrientation(accessibility_object()); +} + +int WebAXObjectProxy::ClickPointX() { + return accessibility_object().clickPoint().x; +} + +int WebAXObjectProxy::ClickPointY() { + return accessibility_object().clickPoint().y; +} + +int32_t WebAXObjectProxy::RowCount() { + return static_cast<int32_t>(accessibility_object().rowCount()); +} + +int32_t WebAXObjectProxy::ColumnCount() { + return static_cast<int32_t>(accessibility_object().columnCount()); +} + +bool WebAXObjectProxy::IsClickable() { + return accessibility_object().isClickable(); +} + +std::string WebAXObjectProxy::AllAttributes() { + return GetAttributes(accessibility_object()); +} + +std::string WebAXObjectProxy::AttributesOfChildren() { + AttributesCollector collector; + unsigned size = accessibility_object().childCount(); + for (unsigned i = 0; i < size; ++i) + collector.CollectAttributes(accessibility_object().childAt(i)); + return collector.attributes(); +} + +int WebAXObjectProxy::LineForIndex(int index) { + blink::WebVector<int> line_breaks; + accessibility_object().lineBreaks(line_breaks); + int line = 0; + int vector_size = static_cast<int>(line_breaks.size()); + while (line < vector_size && line_breaks[line] <= index) + line++; + return line; +} + +std::string WebAXObjectProxy::BoundsForRange(int start, int end) { + if (accessibility_object().role() != blink::WebAXRoleStaticText) + return std::string(); + + int len = end - start; + + // Get the bounds for each character and union them into one large rectangle. + // This is just for testing so it doesn't need to be efficient. + blink::WebRect bounds = BoundsForCharacter(accessibility_object(), start); + for (int i = 1; i < len; i++) { + blink::WebRect next = BoundsForCharacter(accessibility_object(), start + i); + int right = std::max(bounds.x + bounds.width, next.x + next.width); + int bottom = std::max(bounds.y + bounds.height, next.y + next.height); + bounds.x = std::min(bounds.x, next.x); + bounds.y = std::min(bounds.y, next.y); + bounds.width = right - bounds.x; + bounds.height = bottom - bounds.y; + } + + return base::StringPrintf("{x: %d, y: %d, width: %d, height: %d}", + bounds.x, bounds.y, bounds.width, bounds.height); +} + +v8::Handle<v8::Object> WebAXObjectProxy::ChildAtIndex(int index) { + return GetChildAtIndex(index); +} + +v8::Handle<v8::Object> WebAXObjectProxy::ElementAtPoint(int x, int y) { + blink::WebPoint point(x, y); + blink::WebAXObject obj = accessibility_object().hitTest(point); + if (obj.isNull()) + return v8::Handle<v8::Object>(); + + return factory_->GetOrCreate(obj); +} + +v8::Handle<v8::Object> WebAXObjectProxy::TableHeader() { + blink::WebAXObject obj = accessibility_object().headerContainerObject(); + if (obj.isNull()) + return v8::Handle<v8::Object>(); + + return factory_->GetOrCreate(obj); +} + +std::string WebAXObjectProxy::RowIndexRange() { + unsigned row_index = accessibility_object().cellRowIndex(); + unsigned row_span = accessibility_object().cellRowSpan(); + return base::StringPrintf("{%d, %d}", row_index, row_span); +} + +std::string WebAXObjectProxy::ColumnIndexRange() { + unsigned column_index = accessibility_object().cellColumnIndex(); + unsigned column_span = accessibility_object().cellColumnSpan(); + return base::StringPrintf("{%d, %d}", column_index, column_span); +} + +v8::Handle<v8::Object> WebAXObjectProxy::CellForColumnAndRow( + int column, int row) { + blink::WebAXObject obj = + accessibility_object().cellForColumnAndRow(column, row); + if (obj.isNull()) + return v8::Handle<v8::Object>(); + + return factory_->GetOrCreate(obj); +} + +v8::Handle<v8::Object> WebAXObjectProxy::TitleUIElement() { + blink::WebAXObject obj = accessibility_object().titleUIElement(); + if (obj.isNull()) + return v8::Handle<v8::Object>(); + + return factory_->GetOrCreate(obj); +} + +void WebAXObjectProxy::SetSelectedTextRange(int selection_start, + int length) { + accessibility_object().setSelectedTextRange(selection_start, + selection_start + length); +} + +bool WebAXObjectProxy::IsAttributeSettable(const std::string& attribute) { + bool settable = false; + if (attribute == "AXValue") + settable = accessibility_object().canSetValueAttribute(); + return settable; +} + +bool WebAXObjectProxy::IsPressActionSupported() { + return accessibility_object().canPress(); +} + +bool WebAXObjectProxy::IsIncrementActionSupported() { + return accessibility_object().canIncrement(); +} + +bool WebAXObjectProxy::IsDecrementActionSupported() { + return accessibility_object().canDecrement(); +} + +v8::Handle<v8::Object> WebAXObjectProxy::ParentElement() { + blink::WebAXObject parent_object = accessibility_object().parentObject(); + while (parent_object.accessibilityIsIgnored()) + parent_object = parent_object.parentObject(); + return factory_->GetOrCreate(parent_object); +} + +void WebAXObjectProxy::Increment() { + accessibility_object().increment(); +} + +void WebAXObjectProxy::Decrement() { + accessibility_object().decrement(); +} + +void WebAXObjectProxy::ShowMenu() { +} + +void WebAXObjectProxy::Press() { + accessibility_object().press(); +} + +bool WebAXObjectProxy::IsEqual(v8::Handle<v8::Object> proxy) { + WebAXObjectProxy* unwrapped_proxy = NULL; + if (!gin::ConvertFromV8(blink::mainThreadIsolate(), proxy, &unwrapped_proxy)) + return false; + return unwrapped_proxy->IsEqualToObject(accessibility_object_); +} + +void WebAXObjectProxy::SetNotificationListener( + v8::Handle<v8::Function> callback) { + v8::Isolate* isolate = blink::mainThreadIsolate(); + notification_callback_.Reset(isolate, callback); +} + +void WebAXObjectProxy::UnsetNotificationListener() { + notification_callback_.Reset(); +} + +void WebAXObjectProxy::TakeFocus() { + accessibility_object().setFocused(true); +} + +void WebAXObjectProxy::ScrollToMakeVisible() { + accessibility_object().scrollToMakeVisible(); +} + +void WebAXObjectProxy::ScrollToMakeVisibleWithSubFocus(int x, int y, + int width, int height) { + accessibility_object().scrollToMakeVisibleWithSubFocus( + blink::WebRect(x, y, width, height)); +} + +void WebAXObjectProxy::ScrollToGlobalPoint(int x, int y) { + accessibility_object().scrollToGlobalPoint(blink::WebPoint(x, y)); +} + +int WebAXObjectProxy::WordStart(int character_index) { + if (accessibility_object().role() != blink::WebAXRoleStaticText) + return -1; + + int word_start, word_end; + GetBoundariesForOneWord(accessibility_object(), character_index, + word_start, word_end); + return word_start; +} + +int WebAXObjectProxy::WordEnd(int character_index) { + if (accessibility_object().role() != blink::WebAXRoleStaticText) + return -1; + + int word_start, word_end; + GetBoundariesForOneWord(accessibility_object(), character_index, + word_start, word_end); + return word_end; +} + +RootWebAXObjectProxy::RootWebAXObjectProxy( + const blink::WebAXObject &object, Factory *factory) + : WebAXObjectProxy(object, factory) { +} + +v8::Handle<v8::Object> RootWebAXObjectProxy::GetChildAtIndex(unsigned index) { + if (index) + return v8::Handle<v8::Object>(); + + return factory()->GetOrCreate(accessibility_object()); +} + +bool RootWebAXObjectProxy::IsRoot() const { + return true; +} + +WebAXObjectProxyList::WebAXObjectProxyList() { +} + +WebAXObjectProxyList::~WebAXObjectProxyList() { + Clear(); +} + +void WebAXObjectProxyList::Clear() { + for (ElementList::iterator i = elements_.begin(); i != elements_.end(); ++i) + i->Dispose(); + elements_.clear(); +} + +v8::Handle<v8::Object> WebAXObjectProxyList::GetOrCreate( + const blink::WebAXObject& object) { + if (object.isNull()) + return v8::Handle<v8::Object>(); + + v8::Isolate* isolate = blink::mainThreadIsolate(); + + size_t elementCount = elements_.size(); + for (size_t i = 0; i < elementCount; i++) { + WebAXObjectProxy* unwrapped_object = NULL; + bool result = gin::ConvertFromV8(isolate, elements_[i].NewLocal(isolate), + &unwrapped_object); + DCHECK(result); + DCHECK(unwrapped_object); + if (unwrapped_object->IsEqualToObject(object)) + return elements_[i].NewLocal(isolate); + } + + v8::Handle<v8::Object> handle = gin::CreateHandle( + isolate, new WebAXObjectProxy(object, this)).ToV8()->ToObject(); + UnsafePersistent<v8::Object> unsafe_handle(isolate, handle); + elements_.push_back(unsafe_handle); + return unsafe_handle.NewLocal(isolate); +} + +v8::Handle<v8::Object> WebAXObjectProxyList::CreateRoot( + const blink::WebAXObject& object) { + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::Handle<v8::Object> handle = gin::CreateHandle( + isolate, new RootWebAXObjectProxy(object, this)).ToV8()->ToObject(); + UnsafePersistent<v8::Object> unsafe_handle(isolate, handle); + elements_.push_back(unsafe_handle); + return unsafe_handle.NewLocal(isolate); +} + +} // namespace content diff --git a/content/shell/renderer/test_runner/web_ax_object_proxy.h b/content/shell/renderer/test_runner/web_ax_object_proxy.h new file mode 100644 index 0000000..b10b5e8 --- /dev/null +++ b/content/shell/renderer/test_runner/web_ax_object_proxy.h @@ -0,0 +1,168 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_WEB_AX_OBJECT_PROXY_H_ +#define CONTENT_SHELL_RENDERER_TEST_RUNNER_WEB_AX_OBJECT_PROXY_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "content/shell/renderer/test_runner/unsafe_persistent.h" +#include "gin/object_template_builder.h" +#include "gin/wrappable.h" +#include "third_party/WebKit/public/web/WebAXObject.h" +#include "v8/include/v8.h" + +namespace blink { +class WebFrame; +} + +namespace content { + +class WebAXObjectProxy : public gin::Wrappable<WebAXObjectProxy> { + public: + class Factory { + public: + virtual ~Factory() { } + virtual v8::Handle<v8::Object> GetOrCreate( + const blink::WebAXObject& object) = 0; + }; + + static gin::WrapperInfo kWrapperInfo; + + WebAXObjectProxy(const blink::WebAXObject& object, Factory* factory); + virtual ~WebAXObjectProxy(); + + // gin::Wrappable: + virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; + + virtual v8::Handle<v8::Object> GetChildAtIndex(unsigned index); + virtual bool IsRoot() const; + bool IsEqualToObject(const blink::WebAXObject& object); + + void NotificationReceived(blink::WebFrame* frame, + const std::string& notification_name); + + protected: + const blink::WebAXObject& accessibility_object() const { + return accessibility_object_; + } + + Factory* factory() const { return factory_; } + + private: + friend class WebAXObjectProxyBindings; + + // Bound properties. + std::string Role(); + std::string Title(); + std::string Description(); + std::string HelpText(); + std::string StringValue(); + int X(); + int Y(); + int Width(); + int Height(); + int IntValue(); + int MinValue(); + int MaxValue(); + std::string ValueDescription(); + int ChildrenCount(); + int InsertionPointLineNumber(); + std::string SelectedTextRange(); + bool IsEnabled(); + bool IsRequired(); + bool IsFocused(); + bool IsFocusable(); + bool IsSelected(); + bool IsSelectable(); + bool IsMultiSelectable(); + bool IsSelectedOptionActive(); + bool IsExpanded(); + bool IsChecked(); + bool IsVisible(); + bool IsOffScreen(); + bool IsCollapsed(); + bool HasPopup(); + bool IsValid(); + bool IsReadOnly(); + std::string Orientation(); + int ClickPointX(); + int ClickPointY(); + int32_t RowCount(); + int32_t ColumnCount(); + bool IsClickable(); + + // Bound methods. + std::string AllAttributes(); + std::string AttributesOfChildren(); + int LineForIndex(int index); + std::string BoundsForRange(int start, int end); + v8::Handle<v8::Object> ChildAtIndex(int index); + v8::Handle<v8::Object> ElementAtPoint(int x, int y); + v8::Handle<v8::Object> TableHeader(); + std::string RowIndexRange(); + std::string ColumnIndexRange(); + v8::Handle<v8::Object> CellForColumnAndRow(int column, int row); + v8::Handle<v8::Object> TitleUIElement(); + void SetSelectedTextRange(int selection_start, int length); + bool IsAttributeSettable(const std::string& attribute); + bool IsPressActionSupported(); + bool IsIncrementActionSupported(); + bool IsDecrementActionSupported(); + v8::Handle<v8::Object> ParentElement(); + void Increment(); + void Decrement(); + void ShowMenu(); + void Press(); + bool IsEqual(v8::Handle<v8::Object> proxy); + void SetNotificationListener(v8::Handle<v8::Function> callback); + void UnsetNotificationListener(); + void TakeFocus(); + void ScrollToMakeVisible(); + void ScrollToMakeVisibleWithSubFocus(int x, int y, int width, int height); + void ScrollToGlobalPoint(int x, int y); + int WordStart(int character_index); + int WordEnd(int character_index); + + blink::WebAXObject accessibility_object_; + Factory* factory_; + + v8::Persistent<v8::Function> notification_callback_; + + DISALLOW_COPY_AND_ASSIGN(WebAXObjectProxy); +}; + +class RootWebAXObjectProxy : public WebAXObjectProxy { + public: + RootWebAXObjectProxy(const blink::WebAXObject&, Factory*); + + virtual v8::Handle<v8::Object> GetChildAtIndex(unsigned index) OVERRIDE; + virtual bool IsRoot() const OVERRIDE; +}; + + +// Provides simple lifetime management of the WebAXObjectProxy instances: all +// WebAXObjectProxys ever created from the controller are stored in a list and +// cleared explicitly. +class WebAXObjectProxyList : public WebAXObjectProxy::Factory { + public: + WebAXObjectProxyList(); + virtual ~WebAXObjectProxyList(); + + void Clear(); + virtual v8::Handle<v8::Object> GetOrCreate( + const blink::WebAXObject&) OVERRIDE; + v8::Handle<v8::Object> CreateRoot(const blink::WebAXObject&); + + private: + typedef std::vector<UnsafePersistent<v8::Object> > ElementList; + ElementList elements_; +}; + +} // namespace content + +#endif // CONTENT_SHELL_RENDERER_TEST_RUNNER_WEB_AX_OBJECT_PROXY_H_ |