Diff
Modified: trunk/LayoutTests/ChangeLog (158616 => 158617)
--- trunk/LayoutTests/ChangeLog 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/LayoutTests/ChangeLog 2013-11-05 00:47:32 UTC (rev 158617)
@@ -1,3 +1,18 @@
+2013-11-04 Chris Fleizach <[email protected]>
+
+ AX: Mail attachments at the start of an email are not output by VoiceOver
+ https://bugs.webkit.org/show_bug.cgi?id=123697
+
+ Reviewed by Ryosuke Niwa.
+
+ Add two flavors of this. One where the replaced element has rendered children and one where it does not,
+ which go down two different code paths.
+
+ * platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start-expected.txt: Added.
+ * platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start.html: Added.
+ * platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start-expected.txt: Added.
+ * platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start.html: Added.
+
2013-11-04 Ryosuke Niwa <[email protected]>
REGRESSION(r158586): plugins/refcount-leaks.html fails
Added: trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start-expected.txt (0 => 158617)
--- trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start-expected.txt 2013-11-05 00:47:32 UTC (rev 158617)
@@ -0,0 +1,8 @@
+Object string for BODY range: [ATTACHMENT]b
+This tests object replacements are present in strings when the replaced element is at the beginning of the document and has no rendered children.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start.html (0 => 158617)
--- trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start.html (rev 0)
+++ trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start.html 2013-11-05 00:47:32 UTC (rev 158617)
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+.fakeImage {
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+};
+</style>
+<script src=""
+</head>
+<body id="body">
+<div role="img" aria-label="test" id="image1" class="fakeImage"></div>b
+<div id="console"></div>
+<script>
+
+description("This tests object replacements are present in strings when the replaced element is at the beginning of the document and has no rendered children.")
+
+if (window.testRunner && window.accessibilityController) {
+
+ var body = accessibilityController.rootElement.childAtIndex(0);
+ var start = body.startTextMarker;
+ var end = body.endTextMarker;
+ var textMarkerRange = body.textMarkerRangeForMarkers(start, end);
+ var text = body.stringForTextMarkerRange(textMarkerRange);
+ var replace = text.replace(String.fromCharCode(65532), "[ATTACHMENT]");
+ debug("Object string for BODY range: " + replace);
+
+ // Hide extraneous content.
+ var array = document.getElementById("console").parentNode.childNodes;
+ while (array[0] != document.getElementById("console"))
+ array[0].parentNode.removeChild(array[0]);
+}
+
+</script>
+
+<script src=""
+
+</body>
+</html>
Added: trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start-expected.txt (0 => 158617)
--- trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start-expected.txt 2013-11-05 00:47:32 UTC (rev 158617)
@@ -0,0 +1,9 @@
+Object string for BODY range: [ATTACHMENT]inside
+b
+This tests object replacements are present in strings when the replaced element is at the beginning of the document and there are rendered children
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start.html (0 => 158617)
--- trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start.html (rev 0)
+++ trunk/LayoutTests/platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start.html 2013-11-05 00:47:32 UTC (rev 158617)
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+.fakeImage {
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+};
+</style>
+<script src=""
+</head>
+<body id="body">
+<div role="img" aria-label="test" id="image1" class="fakeImage">inside</div>b
+<div id="console"></div>
+<script>
+
+description("This tests object replacements are present in strings when the replaced element is at the beginning of the document and there are rendered children")
+
+if (window.testRunner && window.accessibilityController) {
+
+ var body = accessibilityController.rootElement.childAtIndex(0);
+ var start = body.startTextMarker;
+ var end = body.endTextMarker;
+ var textMarkerRange = body.textMarkerRangeForMarkers(start, end);
+ var text = body.stringForTextMarkerRange(textMarkerRange);
+ var replace = text.replace(String.fromCharCode(65532), "[ATTACHMENT]");
+ debug("Object string for BODY range: " + replace);
+
+ // Hide extraneous content.
+ var array = document.getElementById("console").parentNode.childNodes;
+ while (array[0] != document.getElementById("console"))
+ array[0].parentNode.removeChild(array[0]);
+}
+
+</script>
+
+<script src=""
+
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (158616 => 158617)
--- trunk/Source/WebCore/ChangeLog 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/ChangeLog 2013-11-05 00:47:32 UTC (rev 158617)
@@ -1,3 +1,36 @@
+2013-11-04 Chris Fleizach <[email protected]>
+
+ AX: Mail attachments at the start of an email are not output by VoiceOver
+ https://bugs.webkit.org/show_bug.cgi?id=123697
+
+ Reviewed by Ryosuke Niwa.
+
+ VoiceOver is expecting that "replaced elements" (attachments in a Mail message in this case) to be
+ represented by the replacement character when asking for a stringForRange.
+
+ However, when that replaced element is at the beginning of the document, the logic does not work because
+ there is a few code places that will take that first Position and advance it forward, not accounting for replaced elements.
+ When using the TextIterator normally, it does account for these, so that's why it's only affecting as at the beginning of the document.
+
+ Also a "replaced element" can be more than just renderer->isReplaced(), hence the externing of the isRendererReplacedElement method
+ and using that it in pertinent places.
+
+ Tests: platform/mac/accessibility/object-replacement-with-no-rendered-children-at-node-start.html
+ platform/mac/accessibility/object-replacement-with-rendered-children-at-node-start.html
+
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::replacedNodeNeedsCharacter):
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (nsStringForReplacedNode):
+ * dom/Position.cpp:
+ (WebCore::Position::isCandidate):
+ * dom/PositionIterator.cpp:
+ * dom/Range.cpp:
+ (WebCore::Range::firstNode):
+ * editing/TextIterator.cpp:
+ (WebCore::isRendererReplacedElement):
+ * editing/TextIterator.h:
+
2013-11-04 Andreas Kling <[email protected]>
Use RenderAncestorIterator in a couple of places.
Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.cpp (158616 => 158617)
--- trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -839,7 +839,7 @@
{
// we should always be given a rendered node and a replaced node, but be safe
// replaced nodes are either attachments (widgets) or images
- if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode())
+ if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode())
return false;
// create an AX object, but skip it if it is not supposed to be seen
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (158616 => 158617)
--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2013-11-05 00:47:32 UTC (rev 158617)
@@ -873,7 +873,7 @@
{
// we should always be given a rendered node and a replaced node, but be safe
// replaced nodes are either attachments (widgets) or images
- if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
+ if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode()) {
ASSERT_NOT_REACHED();
return nil;
}
Modified: trunk/Source/WebCore/dom/Position.cpp (158616 => 158617)
--- trunk/Source/WebCore/dom/Position.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/dom/Position.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -937,6 +937,9 @@
if (m_anchorNode->hasTagName(htmlTag))
return false;
+ if (isRendererReplacedElement(renderer))
+ return !nodeIsUserSelectNone(deprecatedNode()) && atFirstEditingPositionForNode();
+
if (renderer->isRenderBlockFlow()) {
RenderBlock& block = toRenderBlock(*renderer);
if (block.logicalHeight() || m_anchorNode->hasTagName(bodyTag)) {
Modified: trunk/Source/WebCore/dom/PositionIterator.cpp (158616 => 158617)
--- trunk/Source/WebCore/dom/PositionIterator.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/dom/PositionIterator.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -29,6 +29,7 @@
#include "HTMLNames.h"
#include "RenderBlock.h"
#include "RenderText.h"
+#include "TextIterator.h"
#include "htmlediting.h"
namespace WebCore {
Modified: trunk/Source/WebCore/dom/Range.cpp (158616 => 158617)
--- trunk/Source/WebCore/dom/Range.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/dom/Range.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -1550,6 +1550,8 @@
return 0;
if (m_start.container()->offsetInCharacters())
return m_start.container();
+ if (isRendererReplacedElement(m_start.container()->renderer()))
+ return m_start.container();
if (Node* child = m_start.container()->childNode(m_start.offset()))
return child;
if (!m_start.offset())
Modified: trunk/Source/WebCore/editing/TextIterator.cpp (158616 => 158617)
--- trunk/Source/WebCore/editing/TextIterator.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/editing/TextIterator.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -245,7 +245,7 @@
ASSERT(stack.size() == 1 + depthCrossingShadowBoundaries(node));
}
-static bool isRendererReplacedElement(RenderObject* renderer)
+bool isRendererReplacedElement(RenderObject* renderer)
{
if (!renderer)
return false;
Modified: trunk/Source/WebCore/editing/TextIterator.h (158616 => 158617)
--- trunk/Source/WebCore/editing/TextIterator.h 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Source/WebCore/editing/TextIterator.h 2013-11-05 00:47:32 UTC (rev 158617)
@@ -63,6 +63,7 @@
String plainText(const Range*, TextIteratorBehavior defaultBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
PassRefPtr<Range> findPlainText(const Range*, const String&, FindOptions);
+bool isRendererReplacedElement(RenderObject*);
class BitStack {
public:
Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp (158616 => 158617)
--- trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/DumpRenderTree/AccessibilityUIElement.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -747,6 +747,16 @@
return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->accessibilityElementForTextMarker(marker));
}
+static JSValueRef startTextMarkerCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->startTextMarker());
+}
+
+static JSValueRef endTextMarkerCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarker());
+}
+
// Static Value Getters
static JSValueRef getARIADropEffectsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
@@ -1242,6 +1252,16 @@
return 0;
}
+AccessibilityTextMarker AccessibilityUIElement::startTextMarker()
+{
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::endTextMarker()
+{
+ return 0;
+}
+
#endif
// Destruction
@@ -1314,6 +1334,8 @@
{ "selectedChildrenCount", selectedChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "horizontalScrollbar", horizontalScrollbarCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "verticalScrollbar", verticalScrollbarCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "startTextMarker", startTextMarkerCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "endTextMarker", endTextMarkerCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
#if PLATFORM(IOS)
{ "iphoneLabel", getIPhoneLabelCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "iphoneHint", getIPhoneHintCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
Modified: trunk/Tools/DumpRenderTree/AccessibilityUIElement.h (158616 => 158617)
--- trunk/Tools/DumpRenderTree/AccessibilityUIElement.h 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/DumpRenderTree/AccessibilityUIElement.h 2013-11-05 00:47:32 UTC (rev 158617)
@@ -229,6 +229,9 @@
AccessibilityTextMarker previousTextMarker(AccessibilityTextMarker*);
AccessibilityTextMarker nextTextMarker(AccessibilityTextMarker*);
AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker startTextMarker();
+ AccessibilityTextMarker endTextMarker();
+
JSStringRef stringForTextMarkerRange(AccessibilityTextMarkerRange*);
int textMarkerRangeLength(AccessibilityTextMarkerRange*);
bool attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*);
Modified: trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm (158616 => 158617)
--- trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm 2013-11-05 00:47:32 UTC (rev 158617)
@@ -1563,6 +1563,26 @@
return 0;
}
+AccessibilityTextMarker AccessibilityUIElement::startTextMarker()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXStartTextMarker"];
+ return AccessibilityTextMarker(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::endTextMarker()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXEndTextMarker"];
+ return AccessibilityTextMarker(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
#endif // SUPPORTS_AX_TEXTMARKERS
JSStringRef AccessibilityUIElement::supportedActions()
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp (158616 => 158617)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -177,6 +177,8 @@
PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int, int) { return 0; }
PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker*) { return 0; }
PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker*) { return 0; }
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker() { return 0; }
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker() { return 0; }
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; }
bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*) { return false; }
int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker*) { return -1; }
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h (158616 => 158617)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h 2013-11-05 00:47:32 UTC (rev 158617)
@@ -225,6 +225,8 @@
int indexForTextMarker(AccessibilityTextMarker*);
bool isTextMarkerValid(AccessibilityTextMarker*);
PassRefPtr<AccessibilityTextMarker> textMarkerForIndex(int);
+ PassRefPtr<AccessibilityTextMarker> startTextMarker();
+ PassRefPtr<AccessibilityTextMarker> endTextMarker();
// Returns an ordered list of supported actions for an element.
JSRetainPtr<JSStringRef> supportedActions() const;
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl (158616 => 158617)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl 2013-11-05 00:47:32 UTC (rev 158617)
@@ -169,6 +169,8 @@
int indexForTextMarker(AccessibilityTextMarker marker);
boolean isTextMarkerValid(AccessibilityTextMarker marker);
AccessibilityTextMarker textMarkerForIndex(int textIndex);
+ readonly attribute AccessibilityTextMarker startTextMarker;
+ readonly attribute AccessibilityTextMarker endTextMarker;
// Returns an ordered list of supported actions for an element.
readonly attribute DOMString supportedActions;
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp (158616 => 158617)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp 2013-11-05 00:47:32 UTC (rev 158617)
@@ -1468,7 +1468,19 @@
// FIXME: implement
return 0;
}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
+{
+ // FIXME: implement
+ return 0;
+}
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
+{
+ // FIXME: implement
+ return 0;
+}
+
void AccessibilityUIElement::scrollToMakeVisible()
{
// FIXME: implement
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm (158616 => 158617)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm 2013-11-05 00:46:55 UTC (rev 158616)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm 2013-11-05 00:47:32 UTC (rev 158617)
@@ -1542,7 +1542,27 @@
return 0;
}
+
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXStartTextMarker"];
+ return AccessibilityTextMarker::create(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXEndTextMarker"];
+ return AccessibilityTextMarker::create(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs)
{
__block NSMutableString *result = [NSMutableString string];