Reviewed by Adele.
authorharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Sep 2006 01:13:35 +0000 (01:13 +0000)
committerharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Sep 2006 01:13:35 +0000 (01:13 +0000)
        <rdar://problem/4708119> REGRESSION: Cannot observe an AXTextField element directly

        ... and most of
        <rdar://problem/4708022> REGRESSION: TextRange-based attributes are missing from text fields
        <rdar://problem/4709515> REGRESSION: Expose text areas

        Remaining work for those two bugs in new bugs:

        <rdar://problem/4712101> Support NSAccessibilityVisibleCharacterRangeAttribute for AXTextField and AXTextArea elements
        <rdar://problem/4712111> Support NSAccessibilityInsertionPointLineNumberAttribute for AXTextArea elements
        <rdar://problem/4712125> Support setting NSAccessibilitySelectedTextAttribute for AXTextField and AXTextArea elements

        * bridge/AXObjectCache.h:
        (WebCore::AXObjectCache::postNotificationToElement):
        * bridge/mac/AXObjectCacheMac.mm:
        (WebCore::AXObjectCache::postNotification):
        (WebCore::AXObjectCache::postNotificationToElement):
        Removed postNotificationToTopWebArea.
        postNotification now posts to input element or top web area, as appropriate.
        postNotificationToElement posts to the specified element itself.

        * bridge/mac/FrameMac.h:
        * bridge/mac/FrameMac.mm:
        (WebCore::FrameMac::respondToChangedContents):
        Take a selection.  Pass the starting position's renderer to postNotification so that postNotification can post to the appropriate input element, if any.

        * bridge/mac/WebCoreAXObject.h:
        * bridge/mac/WebCoreAXObject.mm:
        (-[WebCoreAXObject isWebArea]):
        (-[WebCoreAXObject isAnchor]):
        (-[WebCoreAXObject isTextRange]):
        New convenience methods.

        (-[WebCoreAXObject role]):
        (-[WebCoreAXObject roleDescription])
        (-[WebCoreAXObject value]):
        (-[WebCoreAXObject accessibilityDescription]):
        Support AXTextField and AXTextArea.

        (-[WebCoreAXObject accessibilityShouldUseUniqueId]):
        Register AXTextField and AXTextArea elements so notifications to them can be observed.

        (-[WebCoreAXObject accessibilityIsIgnored]):
        Use new convenience method isWebArea.

        (-[WebCoreAXObject accessibilityAttributeNames]):
        Simplify the array creation.
        Add text range support.

        (-[WebCoreAXObject accessibilityAttributeValue:]):
        Add text range support.

        (-[WebCoreAXObject canSetFocusAttribute]):
        (-[WebCoreAXObject canSetValueAttribute]):
        (-[WebCoreAXObject canSetTextRangeAttributes]):
        New convenience methods.

        (-[WebCoreAXObject accessibilityIsAttributeSettable:]):
        (-[WebCoreAXObject accessibilitySetValue:forAttribute:]):
        Add text range support.

        (-[WebCoreAXObject observableObject]):
        New to locate text field or text area to notify.

        * dom/Document.cpp:
        (WebCore::Document::updateSelection):
        Post AXSelectedTextChanged notification with new selection's start node.
        postNotification will send it to the input element, if there is one, or the top WebArea.

        (WebCore::Document::implicitClose):
        Use postNotificationToElement now that it acts like the old postNotification.

        * page/Frame.h:
        * page/Frame.cpp:
        (WebCore::Frame::appliedEditing):
        (WebCore::Frame::unappliedEditing):
        (WebCore::Frame::reappliedEditing):
        Pass the selection of interest to respondToChangedContents.

        * page/FrameView.cpp:
        (WebCore::FrameView::layout):
        Use postNotificationToElement now that it acts like the old postNotification.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@16169 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/bridge/AXObjectCache.h
WebCore/bridge/mac/AXObjectCacheMac.mm
WebCore/bridge/mac/FrameMac.h
WebCore/bridge/mac/FrameMac.mm
WebCore/bridge/mac/WebCoreAXObject.h
WebCore/bridge/mac/WebCoreAXObject.mm
WebCore/dom/Document.cpp
WebCore/page/Frame.cpp
WebCore/page/Frame.h
WebCore/page/FrameView.cpp

index 487b80632607a04658a3276dae49b83f3a689c61..61599e02889dd0a0bdf1d56d328bdfd3855b2b31 100644 (file)
@@ -1,3 +1,90 @@
+2006-08-31  David Harrison  <harrison@apple.com>
+
+        Reviewed by Adele.
+
+        <rdar://problem/4708119> REGRESSION: Cannot observe an AXTextField element directly
+
+        ... and most of
+        <rdar://problem/4708022> REGRESSION: TextRange-based attributes are missing from text fields
+        <rdar://problem/4709515> REGRESSION: Expose text areas
+
+        Remaining work for those two bugs in new bugs:
+
+        <rdar://problem/4712101> Support NSAccessibilityVisibleCharacterRangeAttribute for AXTextField and AXTextArea elements
+        <rdar://problem/4712111> Support NSAccessibilityInsertionPointLineNumberAttribute for AXTextArea elements
+        <rdar://problem/4712125> Support setting NSAccessibilitySelectedTextAttribute for AXTextField and AXTextArea elements
+
+        * bridge/AXObjectCache.h:
+        (WebCore::AXObjectCache::postNotificationToElement):
+        * bridge/mac/AXObjectCacheMac.mm:
+        (WebCore::AXObjectCache::postNotification):
+        (WebCore::AXObjectCache::postNotificationToElement):
+        Removed postNotificationToTopWebArea.
+        postNotification now posts to input element or top web area, as appropriate.
+        postNotificationToElement posts to the specified element itself.
+        
+        * bridge/mac/FrameMac.h:
+        * bridge/mac/FrameMac.mm:
+        (WebCore::FrameMac::respondToChangedContents):
+        Take a selection.  Pass the starting position's renderer to postNotification so that postNotification can post to the appropriate input element, if any.
+        
+        * bridge/mac/WebCoreAXObject.h:
+        * bridge/mac/WebCoreAXObject.mm:
+        (-[WebCoreAXObject isWebArea]):
+        (-[WebCoreAXObject isAnchor]):
+        (-[WebCoreAXObject isTextRange]):
+        New convenience methods.
+        
+        (-[WebCoreAXObject role]):
+        (-[WebCoreAXObject roleDescription])        
+        (-[WebCoreAXObject value]):
+        (-[WebCoreAXObject accessibilityDescription]):
+        Support AXTextField and AXTextArea.
+
+        (-[WebCoreAXObject accessibilityShouldUseUniqueId]):
+        Register AXTextField and AXTextArea elements so notifications to them can be observed.
+        
+        (-[WebCoreAXObject accessibilityIsIgnored]):
+        Use new convenience method isWebArea.
+
+        (-[WebCoreAXObject accessibilityAttributeNames]):
+        Simplify the array creation.
+        Add text range support.
+       
+        (-[WebCoreAXObject accessibilityAttributeValue:]):
+        Add text range support.
+       
+        (-[WebCoreAXObject canSetFocusAttribute]):
+        (-[WebCoreAXObject canSetValueAttribute]):
+        (-[WebCoreAXObject canSetTextRangeAttributes]):
+        New convenience methods.
+        
+        (-[WebCoreAXObject accessibilityIsAttributeSettable:]):
+        (-[WebCoreAXObject accessibilitySetValue:forAttribute:]):
+        Add text range support.
+
+        (-[WebCoreAXObject observableObject]):
+        New to locate text field or text area to notify.
+        
+        * dom/Document.cpp:
+        (WebCore::Document::updateSelection):
+        Post AXSelectedTextChanged notification with new selection's start node.
+        postNotification will send it to the input element, if there is one, or the top WebArea.
+        
+        (WebCore::Document::implicitClose):
+        Use postNotificationToElement now that it acts like the old postNotification.
+        
+        * page/Frame.h:
+        * page/Frame.cpp:
+        (WebCore::Frame::appliedEditing):
+        (WebCore::Frame::unappliedEditing):
+        (WebCore::Frame::reappliedEditing):
+        Pass the selection of interest to respondToChangedContents.
+        
+        * page/FrameView.cpp:
+        (WebCore::FrameView::layout):
+        Use postNotificationToElement now that it acts like the old postNotification.
+
 2006-08-31  Adele Peterson  <adele@apple.com>
 
         Reviewed by Darin.
index a9b2786b920b0d2de072fbf6f45c51745f53eea8..275bcd66d6afca1c133f5eca592604db667d9993 100644 (file)
@@ -63,7 +63,7 @@ namespace WebCore {
         
         void childrenChanged(RenderObject*);
         void postNotification(RenderObject*, const String& message);
-        void postNotificationToTopWebArea(RenderObject*, const String& message);
+        void postNotificationToElement(RenderObject*, const String& message);
         void handleFocusedUIElementChanged();
         
         static void enableAccessibility() { gAccessibilityEnabled = true; }
@@ -85,7 +85,7 @@ namespace WebCore {
     inline void AXObjectCache::removeAXID(WebCoreAXObject*) { }
     inline void AXObjectCache::childrenChanged(RenderObject*) { }
     inline void AXObjectCache::postNotification(RenderObject*, const String&) { }
-    inline void AXObjectCache::postNotificationToTopWebArea(RenderObject*, const String&) { }
+    inline void AXObjectCache::postNotificationToElement(RenderObject*, const String&) { }
     inline void AXObjectCache::handleFocusedUIElementChanged() { }
 #endif
 
index 8e53fd0705cd7c51643df58c4fc46e652ba79d46..e291f415c920f1db8600a10ef8281e209e836ba6 100644 (file)
@@ -166,14 +166,23 @@ void AXObjectCache::childrenChanged(RenderObject* renderer)
         [obj childrenChanged];
 }
 
-void AXObjectCache::postNotificationToTopWebArea(RenderObject* renderer, const String& message)
+void AXObjectCache::postNotification(RenderObject* renderer, const String& message)
 {
-    if (renderer)
+    if (!renderer)
+        return;
+    
+    // notifications for text input objects are sent to that object
+    // all others are sent to the top WebArea
+    WebCoreAXObject* obj = [get(renderer) observableObject];
+    if (obj)
+        NSAccessibilityPostNotification(obj, message);
+    else
         NSAccessibilityPostNotification(get(renderer->document()->topDocument()->renderer()), message);
 }
 
-void AXObjectCache::postNotification(RenderObject* renderer, const String& message)
+void AXObjectCache::postNotificationToElement(RenderObject* renderer, const String& message)
 {
+    // send the notification to the specified element itself, not one of its ancestors
     if (renderer)
         NSAccessibilityPostNotification(get(renderer), message);
 }
index 909fe9757e5acb28724890ec46e0044ef12a30de..ec0003be16b913e253d84004648d75b1c07fff21 100644 (file)
@@ -262,7 +262,7 @@ public:
     virtual void issuePasteAndMatchStyleCommand();
     virtual void issueTransposeCommand();
     virtual void respondToChangedSelection(const SelectionController &oldSelection, bool closeTyping);
-    virtual void respondToChangedContents();
+    virtual void respondToChangedContents(const SelectionController &);
     virtual bool isContentEditable() const;
     virtual bool shouldChangeSelection(const SelectionController &oldSelection, const SelectionController &newSelection, EAffinity affinity, bool stillSelecting) const;
     virtual bool shouldDeleteSelection(const SelectionController&) const;
index dcb28bc65a1b306115e18d2fd8d5326c9b3dfcb0..55ee9e0af5cb780a4286aa98c91a940af695eca3 100644 (file)
@@ -3249,10 +3249,13 @@ bool FrameMac::shouldDeleteSelection(const SelectionController &selection) const
     return [_bridge shouldDeleteSelectedDOMRange:[DOMRange _rangeWith:selection.toRange().get()]];
 }
 
-void FrameMac::respondToChangedContents()
+void FrameMac::respondToChangedContents(const SelectionController &selection)
 {
-    if (AXObjectCache::accessibilityEnabled())
-        renderer()->document()->axObjectCache()->postNotificationToTopWebArea(renderer(), "AXValueChanged");
+    if (AXObjectCache::accessibilityEnabled()) {
+        Node* node = selection.start().node();
+        if (node)
+            renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
+    }
     [_bridge respondToChangedContents];
 }
 
index bcb01607c8cfa99cac1f45254037e72360f94dec..2014ca62451178ffdc217e2755b5cb38c9c122fd 100644 (file)
@@ -57,6 +57,8 @@ namespace WebCore {
 - (WebCoreAXObject*)nextSibling;
 - (WebCoreAXObject*)parentObject;
 
+- (WebCoreAXObject*)observableObject;
+
 - (void)childrenChanged;
 - (void)clearChildren;
 
index d1bf38fa51f0c69714caf96999799183932e7d0b..2bd33bdbed88f74ef752b376782742c6f6b5415d 100644 (file)
@@ -33,6 +33,7 @@
 #import "FrameMac.h"
 #import "HTMLAreaElement.h"
 #import "HTMLCollection.h"
+#import "HTMLTextAreaElement.h"
 #import "htmlediting.h"
 #import "HTMLFrameElement.h"
 #import "HTMLInputElement.h"
@@ -43,6 +44,7 @@
 #import "RenderImage.h"
 #import "RenderListMarker.h"
 #import "RenderMenuList.h"
+#import "RenderTextControl.h"
 #import "RenderTheme.h"
 #import "RenderView.h"
 #import "RenderWidget.h"
@@ -76,17 +78,6 @@ using namespace HTMLNames;
     return !m_renderer;
 }
 
-// accessibilityShouldUseUniqueId is an AppKit method we override so that the canvas
-// objects will be given a unique ID, and therefore allow AppKit to know when they
-// become obsolete (e.g. when the user navigates to a new web page, making this one
-// unrendered but not deallocated because it is in the back/forward cache).
-// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
-// appropriate place (e.g. dealloc) to remove these non-retained references from
-// AppKit's id mapping tables.
-- (BOOL)accessibilityShouldUseUniqueId {
-    return m_renderer && m_renderer->isRenderView();
-}
-
 -(void)detach
 {
     // Send unregisterUniqueIdForUIElement unconditionally because if it is
@@ -281,6 +272,20 @@ using namespace HTMLNames;
     }
 }
 
+-(BOOL)isWebArea
+{
+    return m_renderer->isRenderView();
+}
+
+-(BOOL)isAnchor
+{
+    return m_areaElement || (!m_renderer->isImage() && m_renderer->element() && m_renderer->element()->isLink());
+} 
+-(BOOL)isTextControl
+{
+    return m_renderer->isTextField() || m_renderer->isTextArea();
+}
+
 -(BOOL)isAttachment
 {
     // widgets are the replaced elements that we represent to AX as attachments
@@ -366,9 +371,15 @@ static int headingLevel(RenderObject* renderer)
             return NSAccessibilityButtonRole;
         return NSAccessibilityImageRole;
     }
-    if (m_renderer->isRenderView())
+    if ([self isWebArea])
         return @"AXWebArea";
     
+    if (m_renderer->isTextField())
+        return NSAccessibilityTextFieldRole;
+    
+    if (m_renderer->isTextArea())
+        return NSAccessibilityTextAreaRole;
+    
     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
         if (input->inputType() == HTMLInputElement::CHECKBOX)
@@ -377,8 +388,6 @@ static int headingLevel(RenderObject* renderer)
             return NSAccessibilityRadioButtonRole;
         if (input->isTextButton())
             return NSAccessibilityButtonRole;
-        if (input->inputType() == HTMLInputElement::TEXT)
-            return NSAccessibilityTextFieldRole;
     }
     
     if (m_renderer->isMenuList())
@@ -441,6 +450,9 @@ static int headingLevel(RenderObject* renderer)
     if ([role isEqualToString:NSAccessibilityTextFieldRole])
         return NSAccessibilityRoleDescription(NSAccessibilityTextFieldRole, nil);
 
+    if ([role isEqualToString:NSAccessibilityTextAreaRole])
+        return NSAccessibilityRoleDescription(NSAccessibilityTextAreaRole, nil);
+
     if ([role isEqualToString:@"AXWebArea"])
         return UI_STRING("web area", "accessibility role description for web area");
     
@@ -523,7 +535,7 @@ static int headingLevel(RenderObject* renderer)
     if (m_renderer->isListMarker())
         return static_cast<RenderListMarker*>(m_renderer)->text().getNSString();
 
-    if (m_renderer->isRenderView()) {
+    if ([self isWebArea]) {
         if (m_renderer->document()->frame())
             return nil;
         
@@ -544,6 +556,9 @@ static int headingLevel(RenderObject* renderer)
 
     if ([self isHeading])
         return [NSNumber numberWithInt:[self headingLevel]];
+        
+    if ([self isTextControl])
+        return (NSString*)(static_cast<RenderTextControl*>(m_renderer)->text());
 
     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
@@ -552,11 +567,8 @@ static int headingLevel(RenderObject* renderer)
         if (input->inputType() == HTMLInputElement::CHECKBOX ||
             input->inputType() == HTMLInputElement::RADIO)
             return [NSNumber numberWithInt:input->checked()];
-        
-        if (input->isTextField())
-            return (NSString*)input->value();
     }
-    
+
     // FIXME: We might need to implement a value here for more types
     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
     // this would require subclassing or making accessibilityAttributeNames do something other than return a
@@ -617,7 +629,7 @@ static HTMLLabelElement* labelForElement(Element* element)
     } else if ([self isAttachment])
         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
 
-    if (m_renderer->isRenderView()) {
+    if ([self isWebArea]) {
         Node* owner = m_renderer->document()->ownerElement();
         if (owner && (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag))) {
             HTMLFrameElement* frameElement = static_cast<HTMLFrameElement*>(owner);
@@ -673,6 +685,28 @@ static IntRect boundingBoxRect(RenderObject* obj)
     return [NSValue valueWithSize: NSMakeSize(rect.width(), rect.height())];
 }
 
+// accessibilityShouldUseUniqueId is an AppKit method we override so that
+// objects will be given a unique ID, and therefore allow AppKit to know when they
+// become obsolete (e.g. when the user navigates to a new web page, making this one
+// unrendered but not deallocated because it is in the back/forward cache).
+// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
+// appropriate place (e.g. dealloc) to remove these non-retained references from
+// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
+//
+// Registering an object is also required for observing notifications. Only registered objects can be observed.
+- (BOOL)accessibilityShouldUseUniqueId {
+    if (!m_renderer)
+        return NO;
+    
+    if ([self isWebArea])
+        return YES;
+
+    if ([self isTextControl])
+        return YES;
+
+    return NO;
+}
+
 -(BOOL)accessibilityIsIgnored
 {
     // ignore invisible element
@@ -719,14 +753,15 @@ static IntRect boundingBoxRect(RenderObject* obj)
         return NO;
     }
     
-    return (!m_renderer->isListMarker() && !m_renderer->isRenderView());
+    return (!m_renderer->isListMarker() && ![self isWebArea]);
 }
 
 - (NSArray*)accessibilityAttributeNames
 {
     static NSArray* attributes = nil;
-    static NSArray* anchorAttrs = nil;
-    static NSArray* webAreaAttrs = nil;
+    static NSMutableArray* anchorAttrs = nil;
+    static NSMutableArray* webAreaAttrs = nil;
+    static NSMutableArray* textAttrs = nil;
     if (attributes == nil) {
         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
             NSAccessibilitySubroleAttribute,
@@ -749,53 +784,34 @@ static IntRect boundingBoxRect(RenderObject* obj)
             nil];
     }
     if (anchorAttrs == nil) {
-        anchorAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
-            NSAccessibilityRoleDescriptionAttribute,
-            NSAccessibilityChildrenAttribute,
-            NSAccessibilityHelpAttribute,
-            NSAccessibilityParentAttribute,
-            NSAccessibilityPositionAttribute,
-            NSAccessibilitySizeAttribute,
-            NSAccessibilityTitleAttribute,
-            NSAccessibilityValueAttribute,
-            NSAccessibilityFocusedAttribute,
-            NSAccessibilityEnabledAttribute,
-            NSAccessibilityWindowAttribute,
-            @"AXURL",
-            @"AXSelectedTextMarkerRange",
-            @"AXStartTextMarker",
-            @"AXEndTextMarker",
-            @"AXVisited",
-            nil];
+        anchorAttrs = [[NSMutableArray alloc] initWithArray:attributes];
+        [anchorAttrs addObject: NSAccessibilityURLAttribute];
     }
     if (webAreaAttrs == nil) {
-        webAreaAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
-            NSAccessibilityRoleDescriptionAttribute,
-            NSAccessibilityChildrenAttribute,
-            NSAccessibilityHelpAttribute,
-            NSAccessibilityParentAttribute,
-            NSAccessibilityPositionAttribute,
-            NSAccessibilitySizeAttribute,
-            NSAccessibilityTitleAttribute,
-            NSAccessibilityDescriptionAttribute,
-            NSAccessibilityValueAttribute,
-            NSAccessibilityFocusedAttribute,
-            NSAccessibilityEnabledAttribute,
-            NSAccessibilityWindowAttribute,
-            @"AXLinkUIElements",
-            @"AXLoaded",
-            @"AXLayoutCount",
-            @"AXSelectedTextMarkerRange",
-            @"AXStartTextMarker",
-            @"AXEndTextMarker",
-            @"AXVisited",
-            nil];
+        webAreaAttrs = [[NSMutableArray alloc] initWithArray:attributes];
+        [webAreaAttrs addObject: @"AXLinkUIElements"];
+        [webAreaAttrs addObject: @"AXLoaded"];
+        [webAreaAttrs addObject: @"AXLayoutCount"];
+    }
+    if (textAttrs == nil) {
+        textAttrs = [[NSMutableArray alloc] initWithArray:attributes];
+        [textAttrs addObject: NSAccessibilityNumberOfCharactersAttribute];
+        [textAttrs addObject: NSAccessibilitySelectedTextAttribute];
+        [textAttrs addObject: NSAccessibilitySelectedTextRangeAttribute];
+        [textAttrs addObject: NSAccessibilityVisibleCharacterRangeAttribute];
+        [textAttrs addObject: NSAccessibilityInsertionPointLineNumberAttribute];
     }
     
-    if (m_renderer && m_renderer->isRenderView())
+    if (!m_renderer)
+        return attributes;
+
+    if ([self isWebArea])
         return webAreaAttrs;
 
-    if (m_areaElement || (m_renderer && !m_renderer->isImage() && m_renderer->element() && m_renderer->element()->isLink()))
+    if ([self isTextControl])
+        return textAttrs;
+
+    if ([self isAnchor])
         return anchorAttrs;
 
     return attributes;
@@ -935,7 +951,7 @@ static IntRect boundingBoxRect(RenderObject* obj)
         return m_children;
     }
 
-    if (m_renderer->isRenderView()) {
+    if ([self isWebArea]) {
         if ([attributeName isEqualToString: @"AXLinkUIElements"]) {
             NSMutableArray* links = [NSMutableArray arrayWithCapacity: 32];
             RefPtr<HTMLCollection> coll = m_renderer->document()->links();
@@ -958,8 +974,28 @@ static IntRect boundingBoxRect(RenderObject* obj)
             return [NSNumber numberWithInt: (static_cast<RenderView*>(m_renderer)->frameView()->layoutCount())];
     }
     
-    if ([attributeName isEqualToString: @"AXURL"] && 
-        (m_areaElement || (!m_renderer->isImage() && m_renderer->element() && m_renderer->element()->isLink()))) {
+    if ([self isTextControl]) {
+        RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
+        if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute])
+            return [NSNumber numberWithUnsignedInt: textControl->text().length()];
+        if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
+            NSString* text = textControl->text();
+            return [text substringWithRange: NSMakeRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart())];
+        }
+        if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute])
+            return [NSValue valueWithRange: NSMakeRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart())];
+        // TODO: Get actual visible range. <rdar://problem/4712101>
+        if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
+            return [NSValue valueWithRange: NSMakeRange(0, textControl->text().length())];
+        // TODO: Get actual AXInsertionPointLineNumber for a text area. <rdar://problem/4712111>
+        if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
+            if (textControl->selectionStart() != textControl->selectionEnd())
+                return nil;
+            return [NSNumber numberWithUnsignedInt: 0];
+        }
+    }
+    
+    if ([self isAnchor] && [attributeName isEqualToString: NSAccessibilityURLAttribute]) {
         HTMLAnchorElement* anchor = [self anchorElement];
         if (anchor) {
             DeprecatedString s = anchor->getAttribute(hrefAttr).deprecatedString();
@@ -2079,6 +2115,7 @@ static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
     NSString* role = [self role];
     if ([role isEqualToString:@"AXLink"] ||
         [role isEqualToString:NSAccessibilityTextFieldRole] ||
+        [role isEqualToString:NSAccessibilityTextAreaRole] ||
         [role isEqualToString:NSAccessibilityButtonRole] ||
         [role isEqualToString:NSAccessibilityPopUpButtonRole] ||
         [role isEqualToString:NSAccessibilityCheckBoxRole] ||
@@ -2087,14 +2124,15 @@ static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
 
     return NO;
 }
+
 - (BOOL)canSetValueAttribute
 {
-    if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
-        HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
-        return input->isTextField();
-    }
-    
-    return NO;
+    return [self isTextControl];
+}
+
+- (BOOL)canSetTextRangeAttributes
+{
+    return [self isTextControl];
 }
 
 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
@@ -2108,6 +2146,11 @@ static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
         return [self canSetValueAttribute];
 
+    if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
+        [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
+        [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
+        return [self canSetTextRangeAttributes];
+    
     return NO;
 }
 
@@ -2116,6 +2159,7 @@ static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
     WebCoreTextMarkerRange* textMarkerRange = nil;
     NSNumber*               number = nil;
     NSString*               string = nil;
+    NSRange                 range = {0, 0};
 
     // decode the parameter
     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
@@ -2127,6 +2171,9 @@ static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
     else if ([value isKindOfClass:[NSString self]])
         string = value;
     
+    else if ([value isKindOfClass:[NSValue self]])
+        range = [value rangeValue];
+    
     // handle the command
     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
         ASSERT(textMarkerRange);
@@ -2141,14 +2188,37 @@ static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
                 m_renderer->document()->setFocusNode(0);
         }
     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
-        if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
+        if (!string)
+            return;
+        if (m_renderer->isTextField()) {
             HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
-            if (input->isTextField() && string)
-                input->setValue(string);
+            input->setValue(string);
+        } else if (m_renderer->isTextArea()) {
+            HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element());
+            textArea->setValue(string);
+      }
+    } else if ([self isTextControl]) {
+        RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
+        if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
+            // TODO: set selected text (ReplaceSelectionCommand). <rdar://problem/4712125>
+        } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
+            textControl->setSelectionRange(range.location, range.location + range.length);
+        } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
+            // TODO: make range visible (scrollRectToVisible).  <rdar://problem/4712101>
         }
     }
 }
 
+- (WebCoreAXObject*)observableObject
+{
+    for (RenderObject* renderer = m_renderer; renderer && renderer->element(); renderer = renderer->parent()) {
+        if (renderer->isTextField() || renderer->isTextArea())
+            return renderer->document()->axObjectCache()->get(renderer);
+    }
+    
+    return nil;
+}
+
 - (void)childrenChanged
 {
     [self clearChildren];
index e8865f8c98e8ae102c5331cb6160f6514bdeb7d2..bd39b83d95b90ffaca1fc2e10aff42582c4dc7f9 100644 (file)
@@ -1098,7 +1098,7 @@ void Document::updateSelection()
     // FIXME: We no longer blow away the selection before starting an editing operation, so the isNotNull checks below are no 
     // longer a correct way to check for user-level selection changes.
     if (AXObjectCache::accessibilityEnabled() && s.start().isNotNull() && s.end().isNotNull()) {
-        axObjectCache()->postNotificationToTopWebArea(renderer(), "AXSelectedTextChanged");
+        axObjectCache()->postNotification(s.start().node()->renderer(), "AXSelectedTextChanged");
     }
 #endif
 }
@@ -1249,7 +1249,7 @@ void Document::implicitClose()
     }
 #if __APPLE__
     if (renderer() && AXObjectCache::accessibilityEnabled())
-        axObjectCache()->postNotification(renderer(), "AXLoadComplete");
+        axObjectCache()->postNotificationToElement(renderer(), "AXLoadComplete");
 #endif
 
 #ifdef SVG_SUPPORT
index 21c282e42be41c62d6b5749fc244320528539523..fefc1f0ca6fb3734f1fe31688ee46555764bfad6 100644 (file)
@@ -2078,7 +2078,7 @@ void Frame::appliedEditing(PassRefPtr<EditCommand> cmd)
         d->m_lastEditCommand = cmd.get();
         registerCommandForUndo(cmd);
     }
-    respondToChangedContents();
+    respondToChangedContents(sel);
 }
 
 void Frame::unappliedEditing(PassRefPtr<EditCommand> cmd)
@@ -2091,7 +2091,7 @@ void Frame::unappliedEditing(PassRefPtr<EditCommand> cmd)
         
     d->m_lastEditCommand = 0;
     registerCommandForRedo(cmd);
-    respondToChangedContents();
+    respondToChangedContents(sel);
 }
 
 void Frame::reappliedEditing(PassRefPtr<EditCommand> cmd)
@@ -2104,7 +2104,7 @@ void Frame::reappliedEditing(PassRefPtr<EditCommand> cmd)
         
     d->m_lastEditCommand = 0;
     registerCommandForUndo(cmd);
-    respondToChangedContents();
+    respondToChangedContents(sel);
 }
 
 CSSMutableStyleDeclaration *Frame::typingStyle() const
index 3b0469ba6e5e238188fc30a8e2d9be7616d33967..dda3d46f99dd0fa950cbb970ae55b22187a88859 100644 (file)
@@ -569,7 +569,7 @@ public:
   virtual void issuePasteAndMatchStyleCommand() = 0;
   virtual void issueTransposeCommand() = 0;
   virtual void respondToChangedSelection(const SelectionController& oldSelection, bool closeTyping) = 0;
-  virtual void respondToChangedContents() = 0;
+  virtual void respondToChangedContents(const SelectionController &endingSelection) = 0;
   virtual bool shouldChangeSelection(const SelectionController& oldSelection, const SelectionController& newSelection, EAffinity affinity, bool stillSelecting) const = 0;
   virtual void partClearedInBegin() = 0; 
   virtual void saveDocumentState() = 0;
index 9c7fe1bb9433bc3b10775d549402ed97493d954a..5fc574735be6e9d509d37f5f3ef6570408d39e4d 100644 (file)
@@ -505,7 +505,7 @@ void FrameView::layout(bool allowSubtree)
 
 #if __APPLE__
     if (AXObjectCache::accessibilityEnabled())
-        root->document()->axObjectCache()->postNotification(root, "AXLayoutComplete");
+        root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
     updateDashboardRegions();
 #endif