<rdar://problem/5119360> ER - Seed: Google results do not have AXHeading information
[WebKit-https.git] / WebCore / page / mac / WebCoreAXObject.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WebCoreAXObject.h"
28
29 #import "DOMInternal.h"
30 #import "ColorMac.h"
31 #import "Document.h"
32 #import "EventNames.h"
33 #import "FocusController.h"
34 #import "Frame.h"
35 #import "FrameLoader.h"
36 #import "FrameView.h"
37 #import "HTMLAreaElement.h"
38 #import "HTMLCollection.h"
39 #import "HTMLFrameElementBase.h"
40 #import "HTMLImageElement.h"
41 #import "HTMLInputElement.h"
42 #import "HTMLLabelElement.h"
43 #import "HTMLMapElement.h"
44 #import "HTMLNames.h"
45 #import "HTMLSelectElement.h"
46 #import "HTMLTextAreaElement.h"
47 #import "HitTestRequest.h"
48 #import "HitTestResult.h"
49 #import "LocalizedStrings.h"
50 #import "NodeList.h"
51 #import "Page.h"
52 #import "RenderImage.h"
53 #import "RenderListMarker.h"
54 #import "RenderMenuList.h"
55 #import "RenderTextControl.h"
56 #import "RenderTheme.h"
57 #import "RenderView.h"
58 #import "RenderWidget.h"
59 #import "SelectionController.h"
60 #import "SimpleFontData.h"
61 #import "TextIterator.h"
62 #import "WebCoreFrameBridge.h"
63 #import "WebCoreFrameView.h"
64 #import "WebCoreObjCExtras.h"
65 #import "WebCoreViewFactory.h"
66 #import "htmlediting.h"
67 #import "kjs_html.h"
68 #import "visible_units.h"
69 #include <mach-o/dyld.h>
70
71 using namespace WebCore;
72 using namespace EventNames;
73 using namespace HTMLNames;
74
75 @interface WebCoreAXObject (PrivateWebCoreAXObject)
76 // forward declarations as needed
77 - (WebCoreTextMarker*)textMarkerForIndex: (NSNumber*) index lastIndexOK: (BOOL)lastIndexOK;
78 - (id)doAXLineForTextMarker: (WebCoreTextMarker* ) textMarker;
79 @end
80
81 @implementation WebCoreAXObject
82
83 #ifndef BUILDING_ON_TIGER
84 + (void)initialize
85 {
86     WebCoreObjCFinalizeOnMainThread(self);
87 }
88 #endif
89
90 -(id)initWithRenderer:(RenderObject*)renderer
91 {
92     [super init];
93     m_renderer = renderer;
94     return self;
95 }
96
97 -(BOOL)detached
98 {
99     return !m_renderer;
100 }
101
102 -(void)detach
103 {
104     // Send unregisterUniqueIdForUIElement unconditionally because if it is
105     // ever accidently not done (via other bugs in our AX implementation) you
106     // end up with a crash like <rdar://problem/4273149>.  It is safe and not
107     // expensive to send even if the object is not registered.
108     [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self];
109     [m_data release];
110     m_data = 0;
111     [self removeAXObjectID];
112     m_renderer = 0;
113     [self clearChildren];
114 }
115
116 - (void)dealloc
117 {
118     [self detach];
119     [super dealloc];
120 }
121
122 - (void)finalize
123 {
124     [self detach];
125     [super finalize];
126 }
127
128 -(id)data
129 {
130     return m_data;
131 }
132
133 -(void)setData:(id)data
134 {
135     if (!m_renderer)
136         return;
137
138     [data retain];
139     [m_data release];
140     m_data = data;
141 }
142
143 -(HTMLAnchorElement*)anchorElement
144 {
145     // return already-known anchor for image areas
146     if (m_areaElement)
147         return m_areaElement;
148
149     // search up the render tree for a RenderObject with a DOM node.  Defer to an earlier continuation, though.
150     RenderObject* currRenderer;
151     for (currRenderer = m_renderer; currRenderer && !currRenderer->element(); currRenderer = currRenderer->parent()) {
152         if (currRenderer->continuation())
153             return [currRenderer->document()->axObjectCache()->get(currRenderer->continuation()) anchorElement];
154     }
155     
156     // bail of none found
157     if (!currRenderer)
158         return 0;
159     
160     // search up the DOM tree for an anchor element
161     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
162     Node* elt = currRenderer->element();
163     for ( ; elt; elt = elt->parentNode()) {
164         if (elt->isLink() && elt->renderer() && !elt->renderer()->isImage())
165             return static_cast<HTMLAnchorElement*>(elt);
166     }
167   
168     return 0;
169 }
170
171 -(BOOL)isImageButton
172 {
173     return m_renderer->isImage() && m_renderer->element() && m_renderer->element()->hasTagName(inputTag);
174 }
175
176 -(Element*)mouseButtonListener
177 {
178     // FIXME: Do the continuation search like anchorElement does
179     for (EventTargetNode* elt = static_cast<EventTargetNode*>(m_renderer->element()); elt; elt = static_cast<EventTargetNode*>(elt->parentNode())) {
180         if (elt->getHTMLEventListener(clickEvent) || elt->getHTMLEventListener(mousedownEvent) || elt->getHTMLEventListener(mouseupEvent))
181             return static_cast<Element*>(elt);
182     }
183
184     return 0;
185 }
186
187 -(Element*)actionElement
188 {
189     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
190         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
191         if (!input->disabled() && (input->inputType() == HTMLInputElement::CHECKBOX ||
192                                    input->inputType() == HTMLInputElement::RADIO ||
193                                    input->isTextButton()))
194             return input;
195     }
196
197     if ([self isImageButton] || m_renderer->isMenuList())
198         return static_cast<Element*>(m_renderer->element());
199
200     Element* elt = [self anchorElement];
201     if (!elt)
202         elt = [self mouseButtonListener];
203
204     return elt;
205 }
206
207 -(WebCoreAXObject*)firstChild
208 {
209     if (!m_renderer || !m_renderer->firstChild())
210         return nil;
211
212     return m_renderer->document()->axObjectCache()->get(m_renderer->firstChild());
213 }
214
215 -(WebCoreAXObject*)lastChild
216 {
217     if (!m_renderer || !m_renderer->lastChild())
218         return nil;
219
220     return m_renderer->document()->axObjectCache()->get(m_renderer->lastChild());
221 }
222
223 -(WebCoreAXObject*)previousSibling
224 {
225     if (!m_renderer || !m_renderer->previousSibling())
226         return nil;
227
228     return m_renderer->document()->axObjectCache()->get(m_renderer->previousSibling());
229 }
230
231 -(WebCoreAXObject*)nextSibling
232 {
233     if (!m_renderer || !m_renderer->nextSibling())
234         return nil;
235
236     return m_renderer->document()->axObjectCache()->get(m_renderer->nextSibling());
237 }
238
239 -(WebCoreAXObject*)parentObject
240 {
241     if (m_areaElement)
242         return m_renderer->document()->axObjectCache()->get(m_renderer);
243
244     if (!m_renderer || !m_renderer->parent())
245         return nil;
246
247     return m_renderer->document()->axObjectCache()->get(m_renderer->parent());
248 }
249
250 -(WebCoreAXObject*)parentObjectUnignored
251 {
252     WebCoreAXObject* obj = [self parentObject];
253     if ([obj accessibilityIsIgnored])
254         return [obj parentObjectUnignored];
255
256     return obj;
257 }
258
259 -(void)addChildrenToArray:(NSMutableArray*)array
260 {
261     // nothing to add if there is no RenderObject
262     if (!m_renderer)
263         return;
264     
265     // try to add RenderWidget's children, but fall thru if there are none
266     if (m_renderer->isWidget()) {
267         RenderWidget* renderWidget = static_cast<RenderWidget*>(m_renderer);
268         Widget* widget = renderWidget->widget();
269         if (widget) {
270             NSArray* childArr = [(widget->getOuterView()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
271             [array addObjectsFromArray: childArr];
272             return;
273         }
274     }
275     
276     // add all unignored acc children
277     for (WebCoreAXObject* obj = [self firstChild]; obj; obj = [obj nextSibling]) {
278         if ([obj accessibilityIsIgnored])
279             [obj addChildrenToArray: array];
280         else
281             [array addObject: obj];
282     }
283     
284     // for a RenderImage, add the <area> elements as individual accessibility objects
285     if (m_renderer->isImage() && !m_areaElement) {
286         HTMLMapElement* map = static_cast<RenderImage*>(m_renderer)->imageMap();
287         if (map) {
288             for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) {
289                 // add an <area> element for this child if it has a link
290                 // NOTE: can't cache these because they all have the same renderer, which is the cache key, right?
291                 // plus there may be little reason to since they are being added to the handy array
292                 if (current->isLink()) {
293                     WebCoreAXObject* obj = [[[WebCoreAXObject alloc] initWithRenderer: m_renderer] autorelease];
294                     obj->m_areaElement = static_cast<HTMLAreaElement*>(current);
295                     [array addObject: obj];
296                 }
297             }
298         }
299     }
300 }
301
302 -(BOOL)isWebArea
303 {
304     return m_renderer->isRenderView();
305 }
306
307 -(BOOL)isAnchor
308 {
309     return m_areaElement || (!m_renderer->isImage() && m_renderer->element() && m_renderer->element()->isLink());
310
311
312 -(BOOL)isTextControl
313 {
314     return m_renderer->isTextField() || m_renderer->isTextArea();
315 }
316
317 static bool isPasswordFieldElement(Node* node)
318 {
319     if (!node || !node->hasTagName(inputTag))
320         return false;
321     
322     HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
323     return input->inputType() == HTMLInputElement::PASSWORD;
324 }
325
326 -(BOOL)isPasswordField
327 {
328     return m_renderer && isPasswordFieldElement(m_renderer->element());
329 }
330
331 -(BOOL)isAttachment
332 {
333     // widgets are the replaced elements that we represent to AX as attachments
334     BOOL result = m_renderer && m_renderer->isWidget();
335     
336     // assert that a widget is a replaced element that is not an image
337     ASSERT(!result || (m_renderer->isReplaced() && !m_renderer->isImage()));
338     return result;
339 }
340
341 -(NSView*)attachmentView
342 {
343     ASSERT(m_renderer->isReplaced() && m_renderer->isWidget() && !m_renderer->isImage());
344
345     RenderWidget* renderWidget = static_cast<RenderWidget*>(m_renderer);
346     Widget* widget = renderWidget->widget();
347     if (widget)
348          return widget->getView();
349
350     return nil;
351 }
352
353 static int blockquoteLevel(RenderObject* renderer)
354 {
355     int result = 0;
356     for (Node* node = renderer->element(); node; node = node->parent()) {
357         if (node->hasTagName(blockquoteTag))
358             result += 1;
359     }
360     
361     return result;
362 }
363
364 static int headingLevel(RenderObject* renderer)
365 {
366     // headings can be in block flow and non-block flow
367     Node* node = renderer->element();
368     if (!node)
369         return 0;
370     
371     if (node->hasTagName(h1Tag))
372         return 1;
373     
374     if (node->hasTagName(h2Tag))
375         return 2;
376     
377     if (node->hasTagName(h3Tag))
378         return 3;
379     
380     if (node->hasTagName(h4Tag))
381         return 4;
382     
383     if (node->hasTagName(h5Tag))
384         return 5;
385     
386     if (node->hasTagName(h6Tag))
387         return 6;
388
389     return 0;
390 }
391
392 -(int)headingLevel
393 {
394     return headingLevel(m_renderer);
395 }
396
397 -(BOOL)isHeading
398 {
399     return [self headingLevel] != 0;
400 }
401
402 -(NSString*)role
403 {
404     if (!m_renderer)
405         return NSAccessibilityUnknownRole;
406
407     if (m_areaElement)
408         return @"AXLink";
409     if (m_renderer->element() && m_renderer->element()->isLink()) {
410         if (m_renderer->isImage())
411             return @"AXImageMap";
412         return @"AXLink";
413     }
414     if (m_renderer->isListMarker())
415         return @"AXListMarker";
416     if (m_renderer->element() && m_renderer->element()->hasTagName(buttonTag))
417         return NSAccessibilityButtonRole;
418     if (m_renderer->isText())
419         return NSAccessibilityStaticTextRole;
420     if (m_renderer->isImage()) {
421         if ([self isImageButton])
422             return NSAccessibilityButtonRole;
423         return NSAccessibilityImageRole;
424     }
425     if ([self isWebArea])
426         return @"AXWebArea";
427     
428     if (m_renderer->isTextField())
429         return NSAccessibilityTextFieldRole;
430     
431     if (m_renderer->isTextArea())
432         return NSAccessibilityTextAreaRole;
433     
434     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
435         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
436         if (input->inputType() == HTMLInputElement::CHECKBOX)
437             return NSAccessibilityCheckBoxRole;
438         if (input->inputType() == HTMLInputElement::RADIO)
439             return NSAccessibilityRadioButtonRole;
440         if (input->isTextButton())
441             return NSAccessibilityButtonRole;
442     }
443     
444     if (m_renderer->isMenuList())
445         return NSAccessibilityPopUpButtonRole;
446
447     if ([self isHeading])
448         return @"AXHeading";
449         
450     if (m_renderer->isBlockFlow())
451         return NSAccessibilityGroupRole;
452     if ([self isAttachment])
453         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
454
455     return NSAccessibilityUnknownRole;
456 }
457
458 -(NSString*)subrole
459 {
460     if ([self isPasswordField])
461         return NSAccessibilitySecureTextFieldSubrole;
462     
463     if ([self isAttachment]) {
464         NSView* attachmentView = [self attachmentView];
465         if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
466             return [attachmentView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
467         }
468     }
469
470     return nil;
471 }
472
473 -(NSString*)roleDescription
474 {
475     if (!m_renderer)
476         return nil;
477
478     // attachments have the AXImage role, but a different subrole
479     if ([self isAttachment])
480         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
481     
482     // FIXME 3447564: It would be better to call some AppKit API to get these strings
483     // (which would be the best way to localize them)
484     
485     NSString* role = [self role];
486     if ([role isEqualToString:NSAccessibilityButtonRole])
487         return NSAccessibilityRoleDescription(NSAccessibilityButtonRole, [self subrole]);
488     
489     if ([role isEqualToString:NSAccessibilityPopUpButtonRole])
490         return NSAccessibilityRoleDescription(NSAccessibilityPopUpButtonRole, [self subrole]);
491    
492     if ([role isEqualToString:NSAccessibilityStaticTextRole])
493         return NSAccessibilityRoleDescription(NSAccessibilityStaticTextRole, [self subrole]);
494
495     if ([role isEqualToString:NSAccessibilityImageRole])
496         return NSAccessibilityRoleDescription(NSAccessibilityImageRole, [self subrole]);
497     
498     if ([role isEqualToString:NSAccessibilityGroupRole])
499         return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
500     
501     if ([role isEqualToString:NSAccessibilityCheckBoxRole])
502         return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, [self subrole]);
503         
504     if ([role isEqualToString:NSAccessibilityRadioButtonRole])
505         return NSAccessibilityRoleDescription(NSAccessibilityRadioButtonRole, [self subrole]);
506         
507     if ([role isEqualToString:NSAccessibilityTextFieldRole])
508         return NSAccessibilityRoleDescription(NSAccessibilityTextFieldRole, [self subrole]);
509
510     if ([role isEqualToString:NSAccessibilityTextAreaRole])
511         return NSAccessibilityRoleDescription(NSAccessibilityTextAreaRole, [self subrole]);
512
513     if ([role isEqualToString:@"AXWebArea"])
514         return AXWebAreaText();
515     
516     if ([role isEqualToString:@"AXLink"])
517         return AXLinkText();
518     
519     if ([role isEqualToString:@"AXListMarker"])
520         return AXListMarkerText();
521     
522     if ([role isEqualToString:@"AXImageMap"])
523         return AXImageMapText();
524
525     if ([role isEqualToString:@"AXHeading"])
526         return AXHeadingText();
527     
528     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
529 }
530
531 -(NSString*)helpText
532 {
533     if (!m_renderer)
534         return nil;
535
536     if (m_areaElement) {
537         const AtomicString& summary = static_cast<Element*>(m_areaElement)->getAttribute(summaryAttr);
538         if (!summary.isEmpty())
539             return summary;
540         const AtomicString& title = static_cast<Element*>(m_areaElement)->getAttribute(titleAttr);
541         if (!title.isEmpty())
542             return title;
543     }
544
545     for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) {
546         if (curr->element() && curr->element()->isHTMLElement()) {
547             const AtomicString& summary = static_cast<Element*>(curr->element())->getAttribute(summaryAttr);
548             if (!summary.isEmpty())
549                 return summary;
550             const AtomicString& title = static_cast<Element*>(curr->element())->getAttribute(titleAttr);
551             if (!title.isEmpty())
552                 return title;
553         }
554     }
555
556     return nil;
557 }
558
559 -(NSString*)textUnderElement
560 {
561     if (!m_renderer)
562         return nil;
563
564     Node* e = m_renderer->element();
565     Document* d = m_renderer->document();
566     if (e && d) {
567         Frame* p = d->frame();
568         if (p) {
569             // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
570             if (p->document() != d)
571                 return nil;
572             return plainText(rangeOfContents(e).get());
573         }
574     }
575
576     // return nil for anonymous text because it is non-trivial to get
577     // the actual text and, so far, that is not needed
578     return nil;
579 }
580
581 -(id)value
582 {
583     if (!m_renderer || m_areaElement || [self isPasswordField])
584         return nil;
585
586     if (m_renderer->isText())
587         return [self textUnderElement];
588     
589     if (m_renderer->isMenuList())
590         return static_cast<RenderMenuList*>(m_renderer)->text();
591     
592     if (m_renderer->isListMarker())
593         return static_cast<RenderListMarker*>(m_renderer)->text();
594
595     if ([self isWebArea]) {
596         if (m_renderer->document()->frame())
597             return nil;
598         
599         // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here
600         VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0);
601         VisiblePosition endVisiblePosition   = m_renderer->positionForCoordinates(INT_MAX, INT_MAX);
602         if (startVisiblePosition.isNull() || endVisiblePosition.isNull())
603             return nil;
604             
605         return plainText(makeRange(startVisiblePosition, endVisiblePosition).get());
606     }
607     
608     if ([self isAttachment]) {
609         NSView* attachmentView = [self attachmentView];
610         if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 
611             return [attachmentView accessibilityAttributeValue:NSAccessibilityValueAttribute];
612         return nil;
613     }
614     
615     if ([self isHeading])
616         return [NSNumber numberWithInt:[self headingLevel]];
617         
618     if ([self isTextControl])
619         return (NSString*)(static_cast<RenderTextControl*>(m_renderer)->text());
620
621     if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
622         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
623
624         // Checkboxes return their state as an integer. 0 for off, 1 for on.
625         if (input->inputType() == HTMLInputElement::CHECKBOX ||
626             input->inputType() == HTMLInputElement::RADIO)
627             return [NSNumber numberWithInt:input->checked()];
628     }
629
630     // FIXME: We might need to implement a value here for more types
631     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
632     // this would require subclassing or making accessibilityAttributeNames do something other than return a
633     // single static array.
634     return nil;
635 }
636
637 static HTMLLabelElement* labelForElement(Element* element)
638 {
639     RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
640     unsigned len = list->length();
641     for (unsigned i = 0; i < len; i++) {
642         HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
643         if (label->correspondingControl() == element)
644             return label;
645     }
646     
647     return 0;
648 }
649
650 -(NSString*)title
651 {
652     if (!m_renderer || m_areaElement || !m_renderer->element())
653         return nil;
654     
655     if (m_renderer->element()->hasTagName(buttonTag))
656         return [self textUnderElement];
657         
658     if (m_renderer->element()->hasTagName(inputTag)) {
659         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
660         if (input->isTextButton())
661             return input->value();
662
663         HTMLLabelElement* label = labelForElement(input);
664         if (label)
665             return label->innerText();
666     }
667     
668     if (m_renderer->element()->isLink() || [self isHeading])
669         return [self textUnderElement];
670         
671     if ([self isAttachment]) {
672         NSView* attachmentView = [self attachmentView];
673         if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) 
674             return [attachmentView accessibilityAttributeValue:NSAccessibilityTitleAttribute];
675     }
676     
677     return nil;
678 }
679
680 - (NSString*)accessibilityDescription
681 {
682     if (!m_renderer || m_areaElement)
683         return nil;
684     
685     if (m_renderer->isImage()) {
686         if (m_renderer->element() && m_renderer->element()->isHTMLElement()) {
687             const AtomicString& alt = static_cast<Element*>(m_renderer->element())->getAttribute(altAttr);
688             if (alt.isEmpty())
689                 return nil;
690             return alt;
691         }
692     } else if ([self isAttachment]) {
693         NSView* attachmentView = [self attachmentView];
694         if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
695             return [attachmentView accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
696     }
697
698     if ([self isWebArea]) {
699         Document *document = m_renderer->document();
700         Node* owner = document->ownerElement();
701         if (owner) {
702             if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) {
703                 HTMLFrameElementBase* frameElement = static_cast<HTMLFrameElementBase*>(owner);
704                 return frameElement->name();
705             } else if (owner->isHTMLElement()) {
706                 return static_cast<Element*>(owner)->getAttribute(nameAttr);
707             }
708         } else {
709             owner = document->body();
710             if (owner && owner->isHTMLElement()) 
711                 return static_cast<Element*>(owner)->getAttribute(nameAttr);
712         } 
713     }
714     
715     return nil;
716 }
717
718 static IntRect boundingBoxRect(RenderObject* obj)
719 {
720     IntRect rect;
721     if (obj) {
722         if (obj->isInlineContinuation())
723             obj = obj->element()->renderer();
724         Vector<IntRect> rects;
725         int x, y;
726         obj->absolutePosition(x, y);
727         obj->absoluteRects(rects, x, y);
728         const size_t n = rects.size();
729         for (size_t i = 0; i < n; ++i) {
730             IntRect r = rects[i];
731             if (!r.isEmpty()) {
732                 if (obj->style()->hasAppearance())
733                     theme()->adjustRepaintRect(obj, r);
734                 rect.unite(r);
735             }
736         }
737     }
738     return rect;
739 }
740
741 -(NSValue*)position
742 {
743     IntRect rect = m_areaElement ? m_areaElement->getRect(m_renderer) : boundingBoxRect(m_renderer);
744     
745     // The Cocoa accessibility API wants the lower-left corner.
746     NSPoint point = NSMakePoint(rect.x(), rect.bottom());
747     if (m_renderer && m_renderer->view() && m_renderer->view()->frameView()) {
748         NSView* view = m_renderer->view()->frameView()->getDocumentView();
749         point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
750     }
751
752     return [NSValue valueWithPoint: point];
753 }
754
755 -(NSValue*)size
756 {
757     IntRect rect = m_areaElement ? m_areaElement->getRect(m_renderer) : boundingBoxRect(m_renderer);
758     return [NSValue valueWithSize: NSMakeSize(rect.width(), rect.height())];
759 }
760
761 // the closest object for an internal anchor
762 -(id)linkedUIElement
763 {
764     if (![self isAnchor])
765         return nil;
766     
767     HTMLAnchorElement* anchor = [self anchorElement];
768     if (!anchor) 
769         return nil;
770     
771     KURL linkURL = anchor->href();
772     String ref = linkURL.ref();
773     if (ref.isEmpty())
774         return nil;
775     
776     // check if URL is the same as current URL
777     linkURL.setRef("");
778     if (m_renderer->document()->url() != linkURL)
779         return nil;
780     
781     Node* linkedNode = m_renderer->document()->getElementById(ref);
782     if (!linkedNode) {
783         linkedNode = m_renderer->document()->anchors()->namedItem(ref, !m_renderer->document()->inCompatMode());
784         if (!linkedNode)
785             return nil;
786     }
787     
788     // the element we find may not be accessible, keep searching until we find a good one
789     WebCoreAXObject* linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
790     while (linkedAXElement && [linkedAXElement accessibilityIsIgnored]) {
791         linkedNode = linkedNode->traverseNextNode(NULL);
792         if (!linkedNode)
793             return nil;
794         linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
795     }
796     
797     return linkedAXElement;    
798 }
799
800 // accessibilityShouldUseUniqueId is an AppKit method we override so that
801 // objects will be given a unique ID, and therefore allow AppKit to know when they
802 // become obsolete (e.g. when the user navigates to a new web page, making this one
803 // unrendered but not deallocated because it is in the back/forward cache).
804 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
805 // appropriate place (e.g. dealloc) to remove these non-retained references from
806 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
807 //
808 // Registering an object is also required for observing notifications. Only registered objects can be observed.
809 - (BOOL)accessibilityShouldUseUniqueId {
810     if (!m_renderer)
811         return NO;
812     
813     if ([self isWebArea])
814         return YES;
815
816     if ([self isTextControl])
817         return YES;
818
819     return NO;
820 }
821
822 -(BOOL)accessibilityIsIgnored
823 {
824     // ignore invisible element
825     if (!m_renderer || m_renderer->style()->visibility() != VISIBLE)
826         return YES;
827
828     // ignore popup menu items because AppKit does
829     for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
830         if (parent->isMenuList())
831             return YES;
832     }
833     
834     // NOTE: BRs always have text boxes now, so the text box check here can be removed
835     if (m_renderer->isText())
836         return m_renderer->isBR() || !static_cast<RenderText*>(m_renderer)->firstTextBox();
837     
838     // delegate to the attachment
839     if ([self isAttachment])
840         return [[self attachmentView] accessibilityIsIgnored];
841         
842     if ([self isHeading])
843         return NO;
844     
845     if (m_areaElement || (m_renderer->element() && m_renderer->element()->isLink()))
846         return NO;
847
848     // all controls are accessible
849     if (m_renderer->element() && m_renderer->element()->isControl())
850         return NO;
851
852     if (m_renderer->isBlockFlow() && m_renderer->childrenInline())
853         return !static_cast<RenderBlock*>(m_renderer)->firstLineBox() && ![self mouseButtonListener];
854
855     // ignore images seemingly used as spacers
856     if (m_renderer->isImage()) {
857         // informal standard is to ignore images with zero-length alt strings
858         Element* elt = static_cast<Element*>(m_renderer->element());
859         if (elt) {
860             const AtomicString& alt = elt->getAttribute(altAttr);
861             if (alt.isEmpty() && !alt.isNull())
862                 return YES;
863         }
864         
865         // check for one-dimensional image
866         if (m_renderer->height() <= 1 || m_renderer->width() <= 1)
867             return YES;
868         
869         // check whether rendered image was stretched from one-dimensional file image
870         RenderImage* image = static_cast<RenderImage*>(m_renderer);
871         if (image->cachedImage()) {
872             IntSize imageSize = image->cachedImage()->imageSize();
873             return (imageSize.height() <= 1 || imageSize.width() <= 1);
874         }
875         
876         return NO;
877     }
878     
879     return (!m_renderer->isListMarker() && ![self isWebArea]);
880 }
881
882 - (NSArray*)accessibilityAttributeNames
883 {
884     if ([self isAttachment])
885         return [[self attachmentView] accessibilityAttributeNames];
886         
887     static NSArray* attributes = nil;
888     static NSArray* anchorAttrs = nil;
889     static NSArray* webAreaAttrs = nil;
890     static NSArray* textAttrs = nil;
891     NSMutableArray* tempArray;
892     if (attributes == nil) {
893         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
894             NSAccessibilitySubroleAttribute,
895             NSAccessibilityRoleDescriptionAttribute,
896             NSAccessibilityChildrenAttribute,
897             NSAccessibilityHelpAttribute,
898             NSAccessibilityParentAttribute,
899             NSAccessibilityPositionAttribute,
900             NSAccessibilitySizeAttribute,
901             NSAccessibilityTitleAttribute,
902             NSAccessibilityDescriptionAttribute,
903             NSAccessibilityValueAttribute,
904             NSAccessibilityFocusedAttribute,
905             NSAccessibilityEnabledAttribute,
906             NSAccessibilityWindowAttribute,
907             @"AXSelectedTextMarkerRange",
908             @"AXStartTextMarker",
909             @"AXEndTextMarker",
910             @"AXVisited",
911             NSAccessibilityLinkedUIElementsAttribute,
912             nil];
913     }
914     if (anchorAttrs == nil) {
915         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
916         [tempArray addObject: NSAccessibilityURLAttribute];
917         anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
918         [tempArray release];
919     }
920     if (webAreaAttrs == nil) {
921         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
922         [tempArray addObject: @"AXLinkUIElements"];
923         [tempArray addObject: @"AXLoaded"];
924         [tempArray addObject: @"AXLayoutCount"];
925         webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
926         [tempArray release];
927     }
928     if (textAttrs == nil) {
929         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
930         [tempArray addObject: NSAccessibilityNumberOfCharactersAttribute];
931         [tempArray addObject: NSAccessibilitySelectedTextAttribute];
932         [tempArray addObject: NSAccessibilitySelectedTextRangeAttribute];
933         [tempArray addObject: NSAccessibilityVisibleCharacterRangeAttribute];
934         [tempArray addObject: NSAccessibilityInsertionPointLineNumberAttribute];
935         textAttrs = [[NSArray alloc] initWithArray:tempArray];
936         [tempArray release];
937     }
938     
939     if (!m_renderer || [self isPasswordField])
940         return attributes;
941
942     if ([self isWebArea])
943         return webAreaAttrs;
944     
945     if ([self isTextControl])
946         return textAttrs;
947
948     if ([self isAnchor] || m_renderer->isImage())
949         return anchorAttrs;
950
951     return attributes;
952 }
953
954 - (NSArray*)accessibilityActionNames
955 {
956     static NSArray* actions = nil;
957     
958     if (actions == nil) {
959         if ([self actionElement]) 
960             actions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, nil];
961         else if ([self isAttachment])
962             actions = [[[self attachmentView] accessibilityActionNames] retain];
963     }
964
965     return actions;
966 }
967
968 - (NSString*)accessibilityActionDescription:(NSString*)action
969 {
970     // we have no custom actions
971     return NSAccessibilityActionDescription(action);
972 }
973
974 - (void)accessibilityPerformAction:(NSString*)action
975 {
976     if ([action isEqualToString:NSAccessibilityPressAction]) {
977         if ([self isAttachment]) {
978             [[self attachmentView] accessibilityPerformAction:action];
979             return;
980         }
981             
982         Element* actionElement = [self actionElement];
983         if (!actionElement)
984             return;
985         if (Frame* f = actionElement->document()->frame())
986             f->loader()->resetMultipleFormSubmissionProtection();
987         actionElement->accessKeyAction(true);
988     }
989 }
990
991 - (WebCoreTextMarkerRange*) textMarkerRangeFromMarkers: (WebCoreTextMarker*) textMarker1 andEndMarker:(WebCoreTextMarker*) textMarker2
992 {
993     return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2];
994 }
995
996 - (WebCoreTextMarker*) textMarkerForVisiblePosition: (VisiblePosition)visiblePos
997 {
998     if (visiblePos.isNull())
999         return nil;
1000     
1001     if (isPasswordFieldElement(visiblePos.deepEquivalent().node()))
1002         return nil;
1003         
1004     return m_renderer->document()->axObjectCache()->textMarkerForVisiblePosition(visiblePos);
1005 }
1006
1007 - (VisiblePosition) visiblePositionForTextMarker: (WebCoreTextMarker*)textMarker
1008 {
1009     return m_renderer->document()->axObjectCache()->visiblePositionForTextMarker(textMarker);
1010 }
1011
1012 - (VisiblePosition) visiblePositionForStartOfTextMarkerRange: (WebCoreTextMarkerRange*)textMarkerRange
1013 {
1014     return [self visiblePositionForTextMarker:[[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]];
1015 }
1016
1017 - (VisiblePosition) visiblePositionForEndOfTextMarkerRange: (WebCoreTextMarkerRange*) textMarkerRange
1018 {
1019     return [self visiblePositionForTextMarker:[[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]];
1020 }
1021
1022 - (WebCoreTextMarkerRange*) textMarkerRangeFromVisiblePositions: (VisiblePosition) startPosition andEndPos: (VisiblePosition) endPosition
1023 {
1024     WebCoreTextMarker* startTextMarker = [self textMarkerForVisiblePosition: startPosition];
1025     WebCoreTextMarker* endTextMarker   = [self textMarkerForVisiblePosition: endPosition];
1026     return [self textMarkerRangeFromMarkers: startTextMarker andEndMarker:endTextMarker];
1027 }
1028
1029 - (WebCoreTextMarkerRange*)textMarkerRange
1030 {
1031     if (!m_renderer)
1032         return nil;
1033     
1034     // construct VisiblePositions for start and end
1035     Node* node = m_renderer->element();
1036     VisiblePosition visiblePos1 = VisiblePosition(node, 0, VP_DEFAULT_AFFINITY);
1037     VisiblePosition visiblePos2 = VisiblePosition(node, maxDeepOffset(node), VP_DEFAULT_AFFINITY);
1038     
1039     // the VisiblePositions are equal for nodes like buttons, so adjust for that
1040     if (visiblePos1 == visiblePos2) {
1041         visiblePos2 = visiblePos2.next();
1042         if (visiblePos2.isNull())
1043             visiblePos2 = visiblePos1;
1044     }
1045     
1046     WebCoreTextMarker* startTextMarker = [self textMarkerForVisiblePosition: visiblePos1];
1047     WebCoreTextMarker* endTextMarker   = [self textMarkerForVisiblePosition: visiblePos2];
1048     return [self textMarkerRangeFromMarkers: startTextMarker andEndMarker:endTextMarker];
1049 }
1050
1051 - (RenderObject*)topRenderer
1052 {
1053     return m_renderer->document()->topDocument()->renderer();
1054 }
1055
1056 - (FrameView*)frameView
1057 {
1058     return m_renderer->document()->view();
1059 }
1060
1061 - (FrameView*)topFrameView
1062 {
1063     return m_renderer->document()->topDocument()->renderer()->view()->frameView();
1064 }
1065
1066 - (id)accessibilityAttributeValue:(NSString*)attributeName
1067 {
1068     if (!m_renderer)
1069         return nil;
1070
1071     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1072         return [self role];
1073
1074     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1075         return [self subrole];
1076
1077     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1078         return [self roleDescription];
1079     
1080     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1081         if (m_renderer->isRenderView() && m_renderer->view() && m_renderer->view()->frameView())
1082             return m_renderer->view()->frameView()->getView();
1083         return [self parentObjectUnignored];
1084     }
1085
1086     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
1087         if (!m_children) {
1088             m_children = [NSMutableArray arrayWithCapacity: 8];
1089             [m_children retain];
1090             [self addChildrenToArray: m_children];
1091         }
1092         return m_children;
1093     }
1094
1095     if ([self isWebArea]) {
1096         if ([attributeName isEqualToString: @"AXLinkUIElements"]) {
1097             NSMutableArray* links = [NSMutableArray arrayWithCapacity: 32];
1098             RefPtr<HTMLCollection> coll = m_renderer->document()->links();
1099             Node* curr = coll->firstItem();
1100             while (curr) {
1101                 RenderObject* obj = curr->renderer();
1102                 if (obj) {
1103                     WebCoreAXObject* axobj = obj->document()->axObjectCache()->get(obj);
1104                     ASSERT([[axobj role] isEqualToString:@"AXLink"]);
1105                     if (![axobj accessibilityIsIgnored])
1106                         [links addObject: axobj];
1107                 }
1108                 curr = coll->nextItem();
1109             }
1110             return links;
1111         }
1112         if ([attributeName isEqualToString: @"AXLoaded"])
1113             return [NSNumber numberWithBool: (!m_renderer->document()->tokenizer())];
1114         if ([attributeName isEqualToString: @"AXLayoutCount"])
1115             return [NSNumber numberWithInt: (static_cast<RenderView*>(m_renderer)->frameView()->layoutCount())];
1116     }
1117     
1118     if ([self isTextControl]) {
1119         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
1120         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute])
1121             return [self isPasswordField] ? nil : [NSNumber numberWithUnsignedInt: textControl->text().length()];
1122         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1123             if ([self isPasswordField])
1124                 return nil;
1125             NSString* text = textControl->text();
1126             return [text substringWithRange: NSMakeRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart())];
1127         }
1128         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute])
1129             return [self isPasswordField] ? nil : [NSValue valueWithRange: NSMakeRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart())];
1130         // TODO: Get actual visible range. <rdar://problem/4712101>
1131         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1132             return [self isPasswordField] ? nil : [NSValue valueWithRange: NSMakeRange(0, textControl->text().length())];
1133         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1134             if ([self isPasswordField] || textControl->selectionStart() != textControl->selectionEnd())
1135                 return nil;
1136             NSNumber* index = [NSNumber numberWithInt: textControl->selectionStart()];
1137             return [self doAXLineForTextMarker: [self textMarkerForIndex: index lastIndexOK: YES]];
1138         }
1139     }
1140     
1141     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1142         if ([self isAnchor]) {
1143             if (HTMLAnchorElement* anchor = [self anchorElement]) {
1144                 NSURL *href = anchor->href();
1145                 return href;
1146             }
1147         } else if (m_renderer->isImage() && m_renderer->element() && m_renderer->element()->hasTagName(imgTag)) {
1148             NSURL *src = static_cast<HTMLImageElement*>(m_renderer->element())->src();
1149             return src;
1150         }
1151         return nil;
1152     }
1153
1154     if ([attributeName isEqualToString: @"AXVisited"])
1155         return [NSNumber numberWithBool: m_renderer->style()->pseudoState() == PseudoVisited];
1156     
1157     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute])
1158         return [self title];
1159     
1160     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute])
1161         return [self accessibilityDescription];
1162     
1163     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
1164         return [self value];
1165
1166     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1167         return [self helpText];
1168     
1169     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1170         return [NSNumber numberWithBool: (m_renderer->element() && m_renderer->document()->focusedNode() == m_renderer->element())];
1171
1172     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1173         return [NSNumber numberWithBool: m_renderer->element() ? m_renderer->element()->isEnabled() : YES];
1174     
1175     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute])
1176         return [self size];
1177
1178     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1179         return [self position];
1180
1181     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute]) {
1182         if (m_renderer && m_renderer->view() && m_renderer->view()->frameView())
1183             return [m_renderer->view()->frameView()->getView() window];
1184
1185         return nil;
1186     }
1187     
1188     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
1189         // get the selection from the document
1190         Selection selection = [self frameView]->frame()->selectionController()->selection();
1191         if (selection.isNone())
1192             return nil;
1193
1194         return (id) [self textMarkerRangeFromVisiblePositions:selection.visibleStart() andEndPos:selection.visibleEnd()];        
1195     }
1196     
1197     if ([attributeName isEqualToString: @"AXStartTextMarker"])
1198         return (id) [self textMarkerForVisiblePosition: startOfDocument(m_renderer->document())];
1199
1200     if ([attributeName isEqualToString: @"AXEndTextMarker"])
1201         return (id) [self textMarkerForVisiblePosition: endOfDocument(m_renderer->document())];
1202
1203     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute])
1204         return (id) [self linkedUIElement];
1205     
1206     return nil;
1207 }
1208
1209 - (NSArray* )accessibilityParameterizedAttributeNames
1210 {
1211     if ([self isAttachment]) 
1212         return nil;
1213         
1214     static NSArray* paramAttrs = nil;
1215     static NSArray* textParamAttrs = nil;
1216     if (paramAttrs == nil) {
1217         paramAttrs = [[NSArray alloc] initWithObjects:
1218         @"AXUIElementForTextMarker",
1219         @"AXTextMarkerRangeForUIElement",
1220         @"AXLineForTextMarker",
1221         @"AXTextMarkerRangeForLine",
1222         @"AXStringForTextMarkerRange",
1223         @"AXTextMarkerForPosition",
1224         @"AXBoundsForTextMarkerRange",
1225         @"AXAttributedStringForTextMarkerRange",
1226         @"AXTextMarkerRangeForUnorderedTextMarkers",
1227         @"AXNextTextMarkerForTextMarker",
1228         @"AXPreviousTextMarkerForTextMarker",
1229         @"AXLeftWordTextMarkerRangeForTextMarker",
1230         @"AXRightWordTextMarkerRangeForTextMarker",
1231         @"AXLeftLineTextMarkerRangeForTextMarker",
1232         @"AXRightLineTextMarkerRangeForTextMarker",
1233         @"AXSentenceTextMarkerRangeForTextMarker",
1234         @"AXParagraphTextMarkerRangeForTextMarker",
1235         @"AXNextWordEndTextMarkerForTextMarker",
1236         @"AXPreviousWordStartTextMarkerForTextMarker",
1237         @"AXNextLineEndTextMarkerForTextMarker",
1238         @"AXPreviousLineStartTextMarkerForTextMarker",
1239         @"AXNextSentenceEndTextMarkerForTextMarker",
1240         @"AXPreviousSentenceStartTextMarkerForTextMarker",
1241         @"AXNextParagraphEndTextMarkerForTextMarker",
1242         @"AXPreviousParagraphStartTextMarkerForTextMarker",
1243         @"AXStyleTextMarkerRangeForTextMarker",
1244         @"AXLengthForTextMarkerRange",
1245         nil];
1246     }
1247
1248     if (textParamAttrs == nil) {
1249         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
1250         [tempArray addObject: (NSString*)kAXLineForIndexParameterizedAttribute];
1251         [tempArray addObject: (NSString*)kAXRangeForLineParameterizedAttribute];
1252         [tempArray addObject: (NSString*)kAXStringForRangeParameterizedAttribute];
1253         [tempArray addObject: (NSString*)kAXRangeForPositionParameterizedAttribute];
1254         [tempArray addObject: (NSString*)kAXRangeForIndexParameterizedAttribute];
1255         [tempArray addObject: (NSString*)kAXBoundsForRangeParameterizedAttribute];
1256         [tempArray addObject: (NSString*)kAXRTFForRangeParameterizedAttribute];
1257         [tempArray addObject: (NSString*)kAXAttributedStringForRangeParameterizedAttribute];
1258         [tempArray addObject: (NSString*)kAXStyleRangeForIndexParameterizedAttribute];
1259         textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
1260         [tempArray release];
1261     }
1262     
1263     if ([self isPasswordField])
1264         return [NSArray array];
1265     
1266     if (!m_renderer)
1267         return paramAttrs;
1268
1269     if ([self isTextControl])
1270         return textParamAttrs;
1271
1272     return paramAttrs;
1273 }
1274
1275 - (id)doAXUIElementForTextMarker: (WebCoreTextMarker* ) textMarker
1276 {
1277     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1278     if (visiblePos.isNull())
1279         return nil;
1280
1281     RenderObject* obj = visiblePos.deepEquivalent().node()->renderer();
1282     if (!obj)
1283         return nil;
1284     
1285     return obj->document()->axObjectCache()->get(obj);
1286 }
1287
1288 - (id)doAXTextMarkerRangeForUIElement: (id) uiElement
1289 {
1290     return (id)[uiElement textMarkerRange];
1291 }
1292
1293 - (id)doAXLineForTextMarker: (WebCoreTextMarker* ) textMarker
1294 {
1295     unsigned int    lineCount = 0;
1296     VisiblePosition savedVisiblePos;
1297     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1298     if (visiblePos.isNull())
1299         return nil;
1300
1301     // move up until we get to the top
1302     // NOTE: BUG This only takes us to the top of the rootEditableElement, not the top of the
1303     // top document.
1304     while (visiblePos.isNotNull() && !(inSameLine(visiblePos, savedVisiblePos))) {
1305         lineCount += 1;
1306         savedVisiblePos = visiblePos;
1307         visiblePos = previousLinePosition(visiblePos, 0);
1308     }
1309     
1310     return [NSNumber numberWithUnsignedInt:(lineCount - 1)];
1311 }
1312
1313 - (id)doAXTextMarkerRangeForLine: (NSNumber*) lineNumber
1314 {
1315     unsigned lineCount = [lineNumber unsignedIntValue];
1316     if (lineCount == 0 || !m_renderer)
1317         return nil;
1318     
1319     // iterate over the lines
1320     // NOTE: BUG this is wrong when lineNumber is lineCount+1,  because nextLinePosition takes you to the
1321     // last offset of the last line
1322     VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0);
1323     VisiblePosition savedVisiblePos;
1324     while (--lineCount != 0) {
1325         savedVisiblePos = visiblePos;
1326         visiblePos = nextLinePosition(visiblePos, 0);
1327         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
1328             return nil;
1329     }
1330     
1331     // make a caret selection for the marker position, then extend it to the line
1332     // NOTE: ignores results of sel.modify because it returns false when
1333     // starting at an empty line.  The resulting selection in that case
1334     // will be a caret at visiblePos.
1335     SelectionController selectionController;
1336     selectionController.setSelection(Selection(visiblePos));
1337     selectionController.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
1338
1339     // return a marker range for the selection start to end
1340     VisiblePosition startPosition = selectionController.selection().visibleStart();
1341     VisiblePosition endPosition = selectionController.selection().visibleEnd();
1342     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1343 }
1344
1345 static NSString *nsStringForReplacedNode(Node* replacedNode)
1346 {
1347     // we should always be given a rendered node and a replaced node, but be safe
1348     // replaced nodes are either attachments (widgets) or images
1349     if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
1350         ASSERT_NOT_REACHED();
1351         return nil;
1352     }
1353
1354     // create an AX object, but skip it if it is not supposed to be seen
1355     WebCoreAXObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
1356     if ([obj accessibilityIsIgnored])
1357         return nil;
1358     
1359     // use the attachmentCharacter to represent the replaced node
1360     const UniChar attachmentChar = NSAttachmentCharacter;
1361     return [NSString stringWithCharacters:&attachmentChar length:1];
1362 }
1363
1364 - (id)doAXStringForTextMarkerRange: (WebCoreTextMarkerRange*) textMarkerRange
1365 {
1366     // extract the start and end VisiblePosition
1367     VisiblePosition startVisiblePosition = [self visiblePositionForStartOfTextMarkerRange: textMarkerRange];
1368     if (startVisiblePosition.isNull())
1369         return nil;
1370     
1371     VisiblePosition endVisiblePosition = [self visiblePositionForEndOfTextMarkerRange: textMarkerRange];
1372     if (endVisiblePosition.isNull())
1373         return nil;
1374     
1375     NSMutableString* resultString = [[[NSMutableString alloc] init] autorelease];
1376     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
1377     while (!it.atEnd()) {
1378         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1379         if (it.length() != 0) {
1380             [resultString appendString:[NSString stringWithCharacters:it.characters() length:it.length()]];
1381         } else {
1382             // locate the node and starting offset for this replaced range
1383             int exception = 0;
1384             Node* node = it.range()->startContainer(exception);
1385             ASSERT(node == it.range()->endContainer(exception));
1386             int offset = it.range()->startOffset(exception);
1387             NSString* attachmentString = nsStringForReplacedNode(node->childNode(offset));
1388             
1389             // append the replacement string
1390             if (attachmentString)
1391                 [resultString appendString:attachmentString];
1392         }
1393         it.advance();
1394     }
1395     
1396     return [resultString length] > 0 ? resultString : nil;
1397 }
1398
1399 - (id)doAXTextMarkerForPosition: (NSPoint) point
1400 {
1401     // convert absolute point to view coordinates
1402     FrameView* frameView = [self topFrameView];
1403     NSView* view = frameView->getDocumentView();
1404     RenderObject* renderer = [self topRenderer];
1405     Node* innerNode = 0;
1406     
1407     // locate the node containing the point
1408     IntPoint pointResult;
1409     while (1) {
1410         // ask the document layer to hitTest
1411         NSPoint windowCoord = [[view window] convertScreenToBase: point];
1412         IntPoint ourpoint([view convertPoint:windowCoord fromView:nil]);
1413
1414         HitTestRequest request(true, true);
1415         HitTestResult result(ourpoint);
1416         renderer->layer()->hitTest(request, result);
1417         innerNode = result.innerNode();
1418         if (!innerNode || !innerNode->renderer())
1419             return nil;
1420
1421         pointResult = result.localPoint();
1422
1423         // done if hit something other than a widget
1424         renderer = innerNode->renderer();
1425         if (!renderer->isWidget())
1426             break;
1427
1428         // descend into widget (FRAME, IFRAME, OBJECT...)
1429         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1430         if (!widget || !widget->isFrameView())
1431             break;
1432         Frame* frame = static_cast<FrameView*>(widget)->frame();
1433         if (!frame)
1434             break;
1435         Document* document = frame->document();
1436         if (!document)
1437             break;
1438         renderer = document->renderer();
1439         frameView = static_cast<FrameView*>(widget);
1440         view = frameView->getDocumentView();
1441     }
1442     
1443     // get position within the node
1444     VisiblePosition pos = innerNode->renderer()->positionForPoint(pointResult);
1445     return (id) [self textMarkerForVisiblePosition:pos];
1446 }
1447
1448 - (id)doAXBoundsForTextMarkerRange: (WebCoreTextMarkerRange*) textMarkerRange
1449 {
1450     // extract the start and end VisiblePosition
1451     VisiblePosition startVisiblePosition = [self visiblePositionForStartOfTextMarkerRange: textMarkerRange];
1452     if (startVisiblePosition.isNull())
1453         return nil;
1454     
1455     VisiblePosition endVisiblePosition = [self visiblePositionForEndOfTextMarkerRange: textMarkerRange];
1456     if (endVisiblePosition.isNull())
1457         return nil;
1458
1459     IntRect rect1 = startVisiblePosition.caretRect();
1460     IntRect rect2 = endVisiblePosition.caretRect();
1461
1462     // readjust for position at the edge of a line.  This is to exclude line rect that doesn't need to be accounted in the range bounds 
1463     if (rect2.y() != rect1.y()) {
1464         VisiblePosition endOfFirstLine = endOfLine(startVisiblePosition);
1465         if (startVisiblePosition == endOfFirstLine) {
1466             startVisiblePosition.setAffinity(DOWNSTREAM);
1467             rect1 = startVisiblePosition.caretRect();
1468         }
1469         if (endVisiblePosition == endOfFirstLine) {
1470             endVisiblePosition.setAffinity(UPSTREAM);
1471             rect2 = endVisiblePosition.caretRect();
1472         }
1473     }
1474
1475     IntRect ourrect = rect1;
1476     ourrect.unite(rect2);
1477
1478     // try to use the document view from the first position, so that nested WebAreas work,
1479     // but fall back to the top level doc if we do not find it easily
1480     RenderObject* renderer = startVisiblePosition.deepEquivalent().node()->renderer();
1481     FrameView* frameView = renderer ? renderer->document()->view() : 0;
1482     if (!frameView)
1483         frameView = [self frameView];
1484     NSView *view = frameView->getView();
1485
1486     // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
1487     if (rect1.bottom() != rect2.bottom()) {
1488         RefPtr<Range> dataRange = makeRange(startVisiblePosition, endVisiblePosition);
1489         IntRect boundingBox = dataRange->boundingBox();
1490         String rangeString = plainText(dataRange.get());
1491         if (rangeString.length() > 1 && !boundingBox.isEmpty()) 
1492             ourrect = boundingBox;
1493     }
1494  
1495     // convert our rectangle to screen coordinates
1496     NSRect rect = ourrect;
1497     rect = NSOffsetRect(rect, -frameView->contentsX(), -frameView->contentsY());
1498     rect = [view convertRect:rect toView:nil];
1499     rect.origin = [[view window] convertBaseToScreen:rect.origin];
1500
1501     // return the converted rect
1502     return [NSValue valueWithRect:rect];
1503 }
1504
1505 static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
1506 {
1507     // get color information assuming NSDeviceRGBColorSpace 
1508     NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
1509     if (rgbColor == nil)
1510         rgbColor = [NSColor blackColor];
1511     CGFloat components[4];
1512     [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
1513     
1514     // create a new CGColorRef to return
1515     CGColorSpaceRef cgColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1516     CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
1517     CGColorSpaceRelease(cgColorSpace);
1518     CFMakeCollectable(cgColor);
1519     
1520     // check for match with existing color
1521     if (existingColor && CGColorEqualToColor(cgColor, existingColor))
1522         cgColor = nil;
1523         
1524     return cgColor;
1525 }
1526
1527 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
1528 {
1529     if (color) {
1530         CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
1531         CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
1532         if (cgColor) {
1533             [attrString addAttribute:attribute value:(id)cgColor range:range];
1534             CGColorRelease(cgColor);
1535         }
1536     } else
1537         [attrString removeAttribute:attribute range:range];
1538 }
1539
1540 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
1541 {
1542     if (number)
1543         [attrString addAttribute:attribute value:number range:range];
1544     else
1545         [attrString removeAttribute:attribute range:range];
1546 }
1547
1548 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
1549 {
1550     NSDictionary* dict;
1551     
1552     if (font) {
1553         dict = [NSDictionary dictionaryWithObjectsAndKeys:
1554             [font fontName]                             , NSAccessibilityFontNameKey,
1555             [font familyName]                           , NSAccessibilityFontFamilyKey,
1556             [font displayName]                          , NSAccessibilityVisibleNameKey,
1557             [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
1558         nil];
1559
1560         [attrString addAttribute:attribute value:dict range:range];
1561     } else
1562         [attrString removeAttribute:attribute range:range];
1563     
1564 }
1565
1566 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1567 {
1568     RenderStyle* style = renderer->style();
1569
1570     // set basic font info
1571     AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
1572
1573     // set basic colors
1574     AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range);
1575     AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range);
1576
1577     // set super/sub scripting
1578     EVerticalAlign alignment = style->verticalAlign();
1579     if (alignment == SUB)
1580         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
1581     else if (alignment == SUPER)
1582         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
1583     else
1584         [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
1585     
1586     // set shadow
1587     if (style->textShadow())
1588         AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
1589     else
1590         [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
1591     
1592     // set underline and strikethrough
1593     int decor = style->textDecorationsInEffect();
1594     if ((decor & UNDERLINE) == 0) {
1595         [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
1596         [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
1597     }
1598     
1599     if ((decor & LINE_THROUGH) == 0) {
1600         [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
1601         [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
1602     }
1603
1604     if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
1605         // find colors using quirk mode approach (strict mode would use current
1606         // color for all but the root line box, which would use getTextDecorationColors)
1607         Color underline, overline, linethrough;
1608         renderer->getTextDecorationColors(decor, underline, overline, linethrough);
1609         
1610         if ((decor & UNDERLINE) != 0) {
1611             AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
1612             AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
1613         }
1614
1615         if ((decor & LINE_THROUGH) != 0) {
1616             AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
1617             AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
1618         }
1619     }
1620 }
1621
1622 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1623 {
1624     int parentHeadingLevel = headingLevel(renderer->parent());
1625     
1626     if (parentHeadingLevel)
1627         [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
1628     else
1629         [attrString removeAttribute:@"AXHeadingLevel" range:range];
1630 }
1631
1632 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1633 {
1634     int quoteLevel = blockquoteLevel(renderer);
1635     
1636     if (quoteLevel)
1637         [attrString addAttribute:@"AXBlockQuoteLevel" value:[NSNumber numberWithInt:quoteLevel] range:range];
1638     else
1639         [attrString removeAttribute:@"AXBlockQuoteLevel" range:range];
1640 }
1641
1642 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, id element, NSRange range)
1643 {
1644     if (element) {
1645         // make a serialiazable AX object
1646         AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:element];
1647         if (axElement) {
1648             [attrString addAttribute:attribute value:(id)axElement range:range];
1649             CFRelease(axElement);
1650         }
1651     } else
1652         [attrString removeAttribute:attribute range:range];
1653 }
1654
1655 static WebCoreAXObject* AXLinkElementForNode (Node* node)
1656 {
1657     RenderObject* obj = node->renderer();
1658     if (!obj)
1659         return nil;
1660
1661     WebCoreAXObject* axObj = obj->document()->axObjectCache()->get(obj);
1662     HTMLAnchorElement* anchor = [axObj anchorElement];
1663     if (!anchor || !anchor->renderer())
1664         return nil;
1665
1666     return anchor->renderer()->document()->axObjectCache()->get(anchor->renderer());
1667 }
1668
1669 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range)
1670 {
1671     Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node);
1672     Vector<DocumentMarker>::iterator markerIt = markers.begin();
1673
1674     unsigned endOffset = (unsigned)offset + range.length;
1675     for ( ; markerIt != markers.end(); markerIt++) {
1676         DocumentMarker marker = *markerIt;
1677         
1678         if (marker.type != DocumentMarker::Spelling)
1679             continue;
1680         
1681         if (marker.endOffset <= (unsigned)offset)
1682             continue;
1683         
1684         if (marker.startOffset > endOffset)
1685             break;
1686         
1687         // add misspelling attribute for the intersection of the marker and the range
1688         int rStart = range.location + (marker.startOffset - offset);
1689         int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset;
1690         NSRange spellRange = NSMakeRange(rStart, rLength);
1691         AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
1692         
1693         if (marker.endOffset > endOffset + 1)
1694             break;
1695     }
1696 }
1697
1698 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length)
1699 {
1700     // skip invisible text
1701     if (!node->renderer())
1702         return;
1703         
1704     // easier to calculate the range before appending the string
1705     NSRange attrStringRange = NSMakeRange([attrString length], length);
1706     
1707     // append the string from this node
1708     [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
1709
1710     // add new attributes and remove irrelevant inherited ones
1711     // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
1712     // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
1713     // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
1714
1715     // remove inherited attachment from prior AXAttributedStringAppendReplaced
1716     [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
1717     
1718     // set new attributes
1719     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
1720     AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
1721     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
1722     AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange);
1723     
1724     // do spelling last because it tends to break up the range
1725     AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange);
1726 }
1727
1728 - (id)doAXAttributedStringForTextMarkerRange: (WebCoreTextMarkerRange*) textMarkerRange
1729 {
1730     // extract the start and end VisiblePosition
1731     VisiblePosition startVisiblePosition = [self visiblePositionForStartOfTextMarkerRange: textMarkerRange];
1732     if (startVisiblePosition.isNull())
1733         return nil;
1734     
1735     VisiblePosition endVisiblePosition = [self visiblePositionForEndOfTextMarkerRange: textMarkerRange];
1736     if (endVisiblePosition.isNull())
1737         return nil;
1738     
1739     // iterate over the range to build the AX attributed string
1740     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
1741     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
1742     while (!it.atEnd()) {
1743         // locate the node and starting offset for this range
1744         int exception = 0;
1745         Node* node = it.range()->startContainer(exception);
1746         ASSERT(node == it.range()->endContainer(exception));
1747         int offset = it.range()->startOffset(exception);
1748         
1749         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1750         if (it.length() != 0) {
1751             AXAttributedStringAppendText(attrString, node, offset, it.characters(), it.length());
1752         } else {
1753             Node* replacedNode = node->childNode(offset);
1754             NSString *attachmentString = nsStringForReplacedNode(replacedNode);
1755             if (attachmentString) {
1756                 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
1757                 
1758                 // append the placeholder string
1759                 [[attrString mutableString] appendString:attachmentString];
1760                 
1761                 // remove all inherited attributes
1762                 [attrString setAttributes:nil range:attrStringRange];
1763                 
1764                 // add the attachment attribute
1765                 WebCoreAXObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
1766                 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
1767             }
1768         }
1769         it.advance();
1770     }
1771
1772     return [attrString autorelease];
1773 }
1774
1775 - (id)doAXTextMarkerRangeForUnorderedTextMarkers: (NSArray*) markers
1776 {
1777     // get and validate the markers
1778     if ([markers count] < 2)
1779         return nil;
1780     
1781     WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [markers objectAtIndex:0];
1782     WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [markers objectAtIndex:1];
1783     if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1] || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
1784         return nil;
1785     
1786     // convert to VisiblePosition
1787     VisiblePosition visiblePos1 = [self visiblePositionForTextMarker:textMarker1];
1788     VisiblePosition visiblePos2 = [self visiblePositionForTextMarker:textMarker2];
1789     if (visiblePos1.isNull() || visiblePos2.isNull())
1790         return nil;
1791     
1792     WebCoreTextMarker* startTextMarker;
1793     WebCoreTextMarker* endTextMarker;
1794     bool alreadyInOrder;
1795     
1796     // upstream is ordered before downstream for the same position
1797     if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM) 
1798         alreadyInOrder = false;
1799     
1800     // use selection order to see if the positions are in order
1801     else 
1802         alreadyInOrder = Selection(visiblePos1, visiblePos2).isBaseFirst();
1803     
1804     if (alreadyInOrder) {
1805         startTextMarker = textMarker1;
1806         endTextMarker = textMarker2;
1807     } else {
1808         startTextMarker = textMarker2;
1809         endTextMarker = textMarker1;
1810     }
1811     
1812     return (id) [self textMarkerRangeFromMarkers: startTextMarker andEndMarker:endTextMarker];
1813 }
1814
1815 - (id)doAXNextTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
1816 {
1817     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1818     VisiblePosition nextVisiblePos = visiblePos.next();
1819     if (nextVisiblePos.isNull())
1820         return nil;
1821     
1822     return (id) [self textMarkerForVisiblePosition:nextVisiblePos];
1823 }
1824
1825 - (id)doAXPreviousTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
1826 {
1827     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1828     VisiblePosition previousVisiblePos = visiblePos.previous();
1829     if (previousVisiblePos.isNull())
1830         return nil;
1831     
1832     return (id) [self textMarkerForVisiblePosition:previousVisiblePos];
1833 }
1834
1835 - (id)doAXLeftWordTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
1836 {
1837     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1838     VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
1839     VisiblePosition endPosition = endOfWord(startPosition);
1840
1841     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1842 }
1843
1844 - (id)doAXRightWordTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
1845 {
1846     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1847     VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
1848     VisiblePosition endPosition = endOfWord(startPosition);
1849
1850     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1851 }
1852
1853
1854 static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
1855 {
1856     // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
1857     // So let's update the position to include that.
1858     VisiblePosition tempPosition;
1859     VisiblePosition startPosition = visiblePosition;
1860     Position p;
1861     RenderObject* renderer;
1862     while (true) {
1863         tempPosition = startPosition.previous();
1864         if (tempPosition.isNull())
1865             break;
1866         p = tempPosition.deepEquivalent();
1867         if (!p.node())
1868             break;
1869         renderer = p.node()->renderer();
1870         if (!renderer || renderer->inlineBox(p.offset(), tempPosition.affinity()) || (renderer->isRenderBlock() && p.offset() == 0))
1871             break;
1872         startPosition = tempPosition;
1873     }
1874     
1875     return startPosition;
1876 }
1877
1878 - (id)doAXLeftLineTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
1879 {
1880     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1881     if (visiblePos.isNull())
1882         return nil;
1883     
1884     // make a caret selection for the position before marker position (to make sure
1885     // we move off of a line start)
1886     VisiblePosition prevVisiblePos = visiblePos.previous();
1887     if (prevVisiblePos.isNull())
1888         return nil;
1889     
1890     VisiblePosition startPosition = startOfLine(prevVisiblePos);
1891
1892     // keep searching for a valid line start position.  Unless the textmarker is at the very beginning, there should
1893     // always be a valid line range.  However, startOfLine will return null for position next to a floating object, 
1894     // since floating object doesn't really belong to any line.  
1895     // This check will reposition the marker before the floating object, to ensure we get a line start.
1896     if (startPosition.isNull()) {
1897         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
1898             prevVisiblePos = prevVisiblePos.previous();
1899             startPosition = startOfLine(prevVisiblePos);
1900         }
1901     } else 
1902         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1903     
1904     VisiblePosition endPosition = endOfLine(prevVisiblePos);
1905     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1906 }
1907
1908 - (id)doAXRightLineTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
1909 {
1910     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1911     if (visiblePos.isNull())
1912         return nil;
1913     
1914     // make sure we move off of a line end
1915     VisiblePosition nextVisiblePos = visiblePos.next();
1916     if (nextVisiblePos.isNull())
1917         return nil;
1918         
1919     VisiblePosition startPosition = startOfLine(nextVisiblePos);
1920     
1921     // fetch for a valid line start position
1922     if (startPosition.isNull() ) {
1923         startPosition = visiblePos;
1924         nextVisiblePos = nextVisiblePos.next();
1925     } else 
1926         startPosition = updateAXLineStartForVisiblePosition(startPosition);
1927     
1928     VisiblePosition endPosition = endOfLine(nextVisiblePos);
1929
1930     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
1931     // Unless the textmarker is at the very end, there should always be a valid line range.  However, endOfLine will 
1932     // return null for position by a floating object, since floating object doesn't really belong to any line.  
1933     // This check will reposition the marker after the floating object, to ensure we get a line end.
1934     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
1935         nextVisiblePos = nextVisiblePos.next();
1936         endPosition = endOfLine(nextVisiblePos);
1937     }
1938     
1939     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1940 }
1941
1942 - (id)doAXSentenceTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
1943 {
1944     // NOTE: BUG FO 2 IMPLEMENT (currently returns incorrect answer)
1945     // Related? <rdar://problem/3927736> Text selection broken in 8A336
1946     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1947     VisiblePosition startPosition = startOfSentence(visiblePos);
1948     VisiblePosition endPosition = endOfSentence(startPosition);
1949     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1950 }
1951
1952 - (id)doAXParagraphTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
1953 {
1954     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1955     VisiblePosition startPosition = startOfParagraph(visiblePos);
1956     VisiblePosition endPosition = endOfParagraph(startPosition);
1957     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
1958 }
1959
1960 - (id)doAXNextWordEndTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
1961 {
1962     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1963     if (visiblePos.isNull())
1964         return nil;
1965
1966     // make sure we move off of a word end
1967     visiblePos = visiblePos.next();
1968     if (visiblePos.isNull())
1969         return nil;
1970
1971     VisiblePosition endPosition = endOfWord(visiblePos, LeftWordIfOnBoundary);
1972     return (id) [self textMarkerForVisiblePosition:endPosition];
1973 }
1974
1975 - (id)doAXPreviousWordStartTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
1976 {
1977     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1978     if (visiblePos.isNull())
1979         return nil;
1980
1981     // make sure we move off of a word start
1982     visiblePos = visiblePos.previous();
1983     if (visiblePos.isNull())
1984         return nil;
1985     
1986     VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
1987     return (id) [self textMarkerForVisiblePosition:startPosition];
1988 }
1989
1990 - (id)doAXNextLineEndTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
1991 {
1992     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
1993     if (visiblePos.isNull())
1994         return nil;
1995     
1996     // to make sure we move off of a line end
1997     VisiblePosition nextVisiblePos = visiblePos.next();
1998     if (nextVisiblePos.isNull())
1999         return nil;
2000         
2001     VisiblePosition endPosition = endOfLine(nextVisiblePos);
2002
2003     // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
2004     // There are cases like when the position is next to a floating object that'll return null for end of line. This code will avoid returning null.
2005     while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
2006         nextVisiblePos = nextVisiblePos.next();
2007         endPosition = endOfLine(nextVisiblePos);
2008     }
2009     
2010     return (id) [self textMarkerForVisiblePosition: endPosition];
2011 }
2012
2013 - (id)doAXPreviousLineStartTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
2014 {
2015     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
2016     if (visiblePos.isNull())
2017         return nil;
2018     
2019     // make sure we move off of a line start
2020     VisiblePosition prevVisiblePos = visiblePos.previous();
2021     if (prevVisiblePos.isNull())
2022         return nil;
2023         
2024     VisiblePosition startPosition = startOfLine(prevVisiblePos);
2025
2026     // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
2027     // There are cases like when the position is next to a floating object that'll return null for start of line. This code will avoid returning null.
2028     if (startPosition.isNull()) {
2029         while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
2030             prevVisiblePos = prevVisiblePos.previous();
2031             startPosition = startOfLine(prevVisiblePos);
2032         }
2033     } else 
2034         startPosition = updateAXLineStartForVisiblePosition(startPosition);
2035     
2036     return (id) [self textMarkerForVisiblePosition: startPosition];
2037 }
2038
2039 - (id)doAXNextSentenceEndTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
2040 {
2041     // NOTE: BUG FO 2 IMPLEMENT (currently returns incorrect answer)
2042     // Related? <rdar://problem/3927736> Text selection broken in 8A336
2043     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
2044     if (visiblePos.isNull())
2045         return nil;
2046     
2047     // make sure we move off of a sentence end
2048     VisiblePosition nextVisiblePos = visiblePos.next();
2049     if (nextVisiblePos.isNull())
2050         return nil;
2051
2052     // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
2053     // see this empty line.  Instead, return the end position of the empty line. 
2054     VisiblePosition endPosition;
2055     String lineString = plainText(makeRange(startOfLine(visiblePos), endOfLine(visiblePos)).get());
2056     if (lineString.isEmpty())
2057         endPosition = nextVisiblePos;
2058     else
2059         endPosition = endOfSentence(nextVisiblePos);
2060     
2061     return (id) [self textMarkerForVisiblePosition: endPosition];
2062 }
2063
2064 - (id)doAXPreviousSentenceStartTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
2065 {
2066     // NOTE: BUG FO 2 IMPLEMENT (currently returns incorrect answer)
2067     // Related? <rdar://problem/3927736> Text selection broken in 8A336
2068     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
2069     if (visiblePos.isNull())
2070         return nil;
2071
2072     // make sure we move off of a sentence start
2073     VisiblePosition previousVisiblePos = visiblePos.previous();
2074     if (previousVisiblePos.isNull())
2075         return nil;
2076     
2077     // treat empty line as a separate sentence.  
2078     VisiblePosition startPosition;
2079     String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
2080     if (lineString.isEmpty())
2081         startPosition = previousVisiblePos;
2082     else
2083         startPosition = startOfSentence(previousVisiblePos);
2084         
2085     return (id) [self textMarkerForVisiblePosition: startPosition];
2086 }
2087
2088 - (id)doAXNextParagraphEndTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
2089 {
2090     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
2091     if (visiblePos.isNull())
2092         return nil;
2093     
2094     // make sure we move off of a paragraph end
2095     visiblePos = visiblePos.next();
2096     if (visiblePos.isNull())
2097         return nil;
2098
2099     VisiblePosition endPosition = endOfParagraph(visiblePos);
2100     return (id) [self textMarkerForVisiblePosition: endPosition];
2101 }
2102
2103 - (id)doAXPreviousParagraphStartTextMarkerForTextMarker: (WebCoreTextMarker*) textMarker
2104 {
2105     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
2106     if (visiblePos.isNull())
2107         return nil;
2108
2109     // make sure we move off of a paragraph start
2110     visiblePos = visiblePos.previous();
2111     if (visiblePos.isNull())
2112         return nil;
2113
2114     VisiblePosition startPosition = startOfParagraph(visiblePos);
2115     return (id) [self textMarkerForVisiblePosition: startPosition];
2116 }
2117
2118 static VisiblePosition startOfStyleRange (const VisiblePosition visiblePos)
2119 {
2120     RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer();
2121     RenderObject* startRenderer = renderer;
2122     RenderStyle* style = renderer->style();
2123     
2124     // traverse backward by renderer to look for style change
2125     for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
2126         // skip non-leaf nodes
2127         if (r->firstChild())
2128             continue;
2129         
2130         // stop at style change
2131         if (r->style() != style)
2132             break;
2133             
2134         // remember match
2135         startRenderer = r;
2136     }
2137     
2138     return VisiblePosition(startRenderer->node(), 0, VP_DEFAULT_AFFINITY);
2139 }
2140
2141 static VisiblePosition endOfStyleRange (const VisiblePosition visiblePos)
2142 {
2143     RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer();
2144     RenderObject* endRenderer = renderer;
2145     RenderStyle* style = renderer->style();
2146
2147     // traverse forward by renderer to look for style change
2148     for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
2149         // skip non-leaf nodes
2150         if (r->firstChild())
2151             continue;
2152         
2153         // stop at style change
2154         if (r->style() != style)
2155             break;
2156         
2157         // remember match
2158         endRenderer = r;
2159     }
2160     
2161     return VisiblePosition(endRenderer->node(), maxDeepOffset(endRenderer->node()), VP_DEFAULT_AFFINITY);
2162 }
2163
2164 - (id)doAXStyleTextMarkerRangeForTextMarker: (WebCoreTextMarker*) textMarker
2165 {
2166     VisiblePosition visiblePos = [self visiblePositionForTextMarker:textMarker];
2167     if (visiblePos.isNull())
2168         return nil;
2169
2170     VisiblePosition startPosition = startOfStyleRange(visiblePos);
2171     VisiblePosition endPosition = endOfStyleRange(visiblePos);
2172     return (id) [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
2173 }
2174
2175 - (id)doAXLengthForTextMarkerRange: (WebCoreTextMarkerRange*) textMarkerRange
2176 {
2177     // NOTE: BUG Multi-byte support
2178     CFStringRef string = (CFStringRef) [self doAXStringForTextMarkerRange: textMarkerRange];
2179     if (!string)
2180         return nil;
2181
2182     return [NSNumber numberWithInt:CFStringGetLength(string)];
2183 }
2184
2185 // NOTE: Consider providing this utility method as AX API
2186 - (WebCoreTextMarker*)textMarkerForIndex: (NSNumber*) index lastIndexOK: (BOOL)lastIndexOK
2187 {
2188     ASSERT(m_renderer->isTextField() || m_renderer->isTextArea());
2189     RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2190     unsigned int indexValue = [index unsignedIntValue];
2191     
2192     // lastIndexOK specifies whether the position after the last character is acceptable
2193     if (indexValue >= textControl->text().length()) {
2194         if (!lastIndexOK || indexValue > textControl->text().length())
2195             return nil;
2196     }
2197     VisiblePosition position = textControl->visiblePositionForIndex(indexValue);
2198     position.setAffinity(DOWNSTREAM);
2199     return [self textMarkerForVisiblePosition: position];
2200 }
2201
2202 // NOTE: Consider providing this utility method as AX API
2203 - (NSNumber*)indexForTextMarker: (WebCoreTextMarker*) marker
2204 {
2205     ASSERT(m_renderer->isTextField() || m_renderer->isTextArea());
2206     RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2207
2208     VisiblePosition position = [self visiblePositionForTextMarker: marker];
2209     Node* node = position.deepEquivalent().node();
2210     if (!node)
2211         return nil;
2212     
2213     for (RenderObject* renderer = node->renderer(); renderer && renderer->element(); renderer = renderer->parent()) {
2214         if (renderer == textControl)
2215             return [NSNumber numberWithInt: textControl->indexForVisiblePosition(position)];
2216     }
2217     
2218     return nil;
2219 }
2220
2221 // NOTE: Consider providing this utility method as AX API
2222 - (WebCoreTextMarkerRange*)textMarkerRangeForRange: (NSRange) range
2223 {
2224     ASSERT(m_renderer->isTextField() || m_renderer->isTextArea());
2225     RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2226     if (range.location + range.length > textControl->text().length())
2227         return nil;
2228     
2229     VisiblePosition startPosition = textControl->visiblePositionForIndex(range.location);
2230     startPosition.setAffinity(DOWNSTREAM);
2231     VisiblePosition endPosition = textControl->visiblePositionForIndex(range.location + range.length);
2232     return [self textMarkerRangeFromVisiblePositions:startPosition andEndPos:endPosition];
2233 }
2234
2235 // NOTE: Consider providing this utility method as AX API
2236 - (NSValue*)rangeForTextMarkerRange: (WebCoreTextMarkerRange*) textMarkerRange
2237 {
2238     WebCoreTextMarker* textMarker1 = [[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange];
2239     WebCoreTextMarker* textMarker2 = [[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange];
2240     NSNumber* index1 = [self indexForTextMarker: textMarker1];
2241     NSNumber* index2 = [self indexForTextMarker: textMarker2];
2242     if (!index1 || !index2 || [index1 unsignedIntValue] > [index2 unsignedIntValue])
2243         return nil;
2244     
2245     return [NSValue valueWithRange: NSMakeRange([index1 unsignedIntValue], [index2 unsignedIntValue] - [index1 unsignedIntValue])];
2246 }
2247
2248 // Given an indexed character, the line number of the text associated with this accessibility
2249 // object that contains the character.
2250 - (id)doAXLineForIndex: (NSNumber*) index
2251 {
2252     return [self doAXLineForTextMarker: [self textMarkerForIndex: index lastIndexOK: NO]];
2253 }
2254
2255 // Given a line number, the range of characters of the text associated with this accessibility
2256 // object that contains the line number.
2257 - (id)doAXRangeForLine: (NSNumber*) lineNumber
2258 {
2259     ASSERT(m_renderer->isTextField() || m_renderer->isTextArea());
2260     RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2261     
2262     // iterate to the specified line
2263     VisiblePosition visiblePos = textControl->visiblePositionForIndex(0);
2264     VisiblePosition savedVisiblePos;
2265     for (unsigned lineCount = [lineNumber unsignedIntValue]; lineCount != 0; lineCount -= 1) {
2266         savedVisiblePos = visiblePos;
2267         visiblePos = nextLinePosition(visiblePos, 0);
2268         if (visiblePos.isNull() || visiblePos == savedVisiblePos)
2269             return nil;
2270     }
2271     
2272     // make a caret selection for the marker position, then extend it to the line
2273     // NOTE: ignores results of selectionController.modify because it returns false when
2274     // starting at an empty line.  The resulting selection in that case
2275     // will be a caret at visiblePos.
2276     SelectionController selectionController;
2277     selectionController.setSelection(Selection(visiblePos));
2278     selectionController.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary);
2279     selectionController.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
2280     
2281     // calculate the indices for the selection start and end
2282     VisiblePosition startPosition = selectionController.selection().visibleStart();
2283     VisiblePosition endPosition = selectionController.selection().visibleEnd();
2284     int index1 = textControl->indexForVisiblePosition(startPosition);
2285     int index2 = textControl->indexForVisiblePosition(endPosition);
2286     
2287     // add one to the end index for a line break not caused by soft line wrap (to match AppKit)
2288     if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull())
2289         index2 += 1;
2290
2291     // return nil rather than an zero-length range (to match AppKit)
2292     if (index1 == index2)
2293         return nil;
2294     
2295     return [NSValue valueWithRange: NSMakeRange(index1, index2 - index1)];
2296 }
2297
2298 // A substring of the text associated with this accessibility object that is
2299 // specified by the given character range.
2300 - (id)doAXStringForRange: (NSRange) range
2301 {
2302     if ([self isPasswordField])
2303         return nil;
2304         
2305     if (range.length == 0)
2306         return @"";
2307         
2308     ASSERT(m_renderer->isTextField() || m_renderer->isTextArea());
2309     RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2310     String text = textControl->text();
2311     if (range.location + range.length > text.length())
2312         return nil;
2313         
2314     return text.substring(range.location, range.length);
2315 }
2316
2317 // The composed character range in the text associated with this accessibility object that
2318 // is specified by the given screen coordinates. This parameterized attribute returns the
2319 // complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
2320 // screen coordinates.
2321 // NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
2322 // an error in that case. We return textControl->text().length(), 1. Does this matter?
2323 - (id)doAXRangeForPosition: (NSPoint) point
2324 {
2325     NSNumber* index = [self indexForTextMarker: [self doAXTextMarkerForPosition: point]];
2326     if (!index)
2327         return nil;
2328         
2329     return [NSValue valueWithRange: NSMakeRange([index unsignedIntValue], 1)];
2330 }
2331
2332 // The composed character range in the text associated with this accessibility object that
2333 // is specified by the given index value. This parameterized attribute returns the complete
2334 // range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
2335 - (id)doAXRangeForIndex: (NSNumber*) number
2336 {
2337     ASSERT(m_renderer->isTextField() || m_renderer->isTextArea());
2338     RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2339     String text = textControl->text();
2340     if (!text.length() || [number unsignedIntValue] > text.length() - 1)
2341         return nil;
2342     
2343     return [NSValue valueWithRange: NSMakeRange([number unsignedIntValue], 1)];
2344 }
2345
2346 // The bounding rectangle of the text associated with this accessibility object that is
2347 // specified by the given range. This is the bounding rectangle a sighted user would see
2348 // on the display screen, in pixels.
2349 - (id)doAXBoundsForRange: (NSRange) range
2350 {
2351     return [self doAXBoundsForTextMarkerRange: [self textMarkerRangeForRange:range]];
2352 }
2353
2354 // The CFAttributedStringType representation of the text associated with this accessibility
2355 // object that is specified by the given range.
2356 - (id)doAXAttributedStringForRange: (NSRange) range
2357 {
2358     return [self doAXAttributedStringForTextMarkerRange: [self textMarkerRangeForRange:range]];
2359 }
2360
2361 // The RTF representation of the text associated with this accessibility object that is
2362 // specified by the given range.
2363 - (id)doAXRTFForRange: (NSRange) range
2364 {
2365     NSAttributedString* attrString = [self doAXAttributedStringForRange: range];
2366     return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
2367 }
2368
2369 // Given a character index, the range of text associated with this accessibility object
2370 // over which the style in effect at that character index applies.
2371 - (id)doAXStyleRangeForIndex: (NSNumber*) index
2372 {
2373     WebCoreTextMarkerRange* textMarkerRange = [self doAXStyleTextMarkerRangeForTextMarker: [self textMarkerForIndex: index lastIndexOK: NO]];
2374     return [self rangeForTextMarkerRange: textMarkerRange];
2375 }
2376
2377 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
2378 {
2379     WebCoreTextMarker*      textMarker = nil;
2380     WebCoreTextMarkerRange* textMarkerRange = nil;
2381     NSNumber*               number = nil;
2382     NSArray*                array = nil;
2383     WebCoreAXObject*        uiElement = nil;
2384     NSPoint                 point = NSZeroPoint;
2385     bool                    pointSet = false;
2386     NSRange                 range = {0, 0};
2387     bool                    rangeSet = false;
2388     
2389     // basic parameter validation
2390     if (!m_renderer || !attribute || !parameter)
2391         return nil;
2392
2393     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
2394     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
2395     // a parameter of the wrong type.
2396     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
2397         textMarker = (WebCoreTextMarker*) parameter;
2398
2399     else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
2400         textMarkerRange = (WebCoreTextMarkerRange*) parameter;
2401
2402     else if ([parameter isKindOfClass:[WebCoreAXObject self]])
2403         uiElement = (WebCoreAXObject*) parameter;
2404
2405     else if ([parameter isKindOfClass:[NSNumber self]])
2406         number = parameter;
2407
2408     else if ([parameter isKindOfClass:[NSArray self]])
2409         array = parameter;
2410     
2411     else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
2412         pointSet = true;
2413         point = [(NSValue*)parameter pointValue];
2414
2415     } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
2416         rangeSet = true;
2417         range = [(NSValue*)parameter rangeValue];
2418
2419     } else {
2420         // got a parameter of a type we never use
2421         // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally 
2422         // while using accesstool (e.g.), forcing you to start over
2423         return nil;
2424     }
2425   
2426     // dispatch
2427     if ([attribute isEqualToString: @"AXUIElementForTextMarker"])
2428         return [self doAXUIElementForTextMarker: textMarker];
2429
2430     if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"])
2431         return [self doAXTextMarkerRangeForUIElement: uiElement];
2432
2433     if ([attribute isEqualToString: @"AXLineForTextMarker"])
2434         return [self doAXLineForTextMarker: textMarker];
2435
2436     if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"])
2437         return [self doAXTextMarkerRangeForLine: number];
2438
2439     if ([attribute isEqualToString: @"AXStringForTextMarkerRange"])
2440         return [self doAXStringForTextMarkerRange: textMarkerRange];
2441
2442     if ([attribute isEqualToString: @"AXTextMarkerForPosition"])
2443         return pointSet ? [self doAXTextMarkerForPosition: point] : nil;
2444
2445     if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"])
2446         return [self doAXBoundsForTextMarkerRange: textMarkerRange];
2447
2448     if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
2449         return [self doAXAttributedStringForTextMarkerRange: textMarkerRange];
2450
2451     if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"])
2452         return [self doAXTextMarkerRangeForUnorderedTextMarkers: array];
2453
2454     if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"])
2455         return [self doAXNextTextMarkerForTextMarker: textMarker];
2456
2457     if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"])
2458         return [self doAXPreviousTextMarkerForTextMarker: textMarker];
2459
2460     if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"])
2461         return [self doAXLeftWordTextMarkerRangeForTextMarker: textMarker];
2462
2463     if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"])
2464         return [self doAXRightWordTextMarkerRangeForTextMarker: textMarker];
2465
2466     if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"])
2467         return [self doAXLeftLineTextMarkerRangeForTextMarker: textMarker];
2468
2469     if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"])
2470         return [self doAXRightLineTextMarkerRangeForTextMarker: textMarker];
2471
2472     if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"])
2473         return [self doAXSentenceTextMarkerRangeForTextMarker: textMarker];
2474
2475     if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"])
2476         return [self doAXParagraphTextMarkerRangeForTextMarker: textMarker];
2477
2478     if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"])
2479         return [self doAXNextWordEndTextMarkerForTextMarker: textMarker];
2480
2481     if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"])
2482         return [self doAXPreviousWordStartTextMarkerForTextMarker: textMarker];
2483         
2484     if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"])
2485         return [self doAXNextLineEndTextMarkerForTextMarker: textMarker];
2486         
2487     if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"])
2488         return [self doAXPreviousLineStartTextMarkerForTextMarker: textMarker];
2489         
2490     if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"])
2491         return [self doAXNextSentenceEndTextMarkerForTextMarker: textMarker];
2492         
2493     if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"])
2494         return [self doAXPreviousSentenceStartTextMarkerForTextMarker: textMarker];
2495         
2496     if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"])
2497         return [self doAXNextParagraphEndTextMarkerForTextMarker: textMarker];
2498
2499     if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"])
2500         return [self doAXPreviousParagraphStartTextMarkerForTextMarker: textMarker];
2501     
2502     if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"])
2503         return [self doAXStyleTextMarkerRangeForTextMarker: textMarker];
2504     
2505     if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"])
2506         return [self doAXLengthForTextMarkerRange: textMarkerRange];
2507     
2508     if ([self isTextControl]) {
2509         if ([attribute isEqualToString: (NSString*)kAXLineForIndexParameterizedAttribute])
2510             return [self doAXLineForIndex: number];
2511         
2512         if ([attribute isEqualToString: (NSString*)kAXRangeForLineParameterizedAttribute])
2513             return [self doAXRangeForLine: number];
2514         
2515         if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute])
2516             return rangeSet ? [self doAXStringForRange: range] : nil;
2517         
2518         if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute])
2519             return pointSet ? [self doAXRangeForPosition: point] : nil;
2520         
2521         if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute])
2522             return [self doAXRangeForIndex: number];
2523         
2524         if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute])
2525             return rangeSet ? [self doAXBoundsForRange: range] : nil;
2526        
2527         if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
2528             return rangeSet ? [self doAXRTFForRange: range] : nil;
2529         
2530         if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
2531             return rangeSet ? [self doAXAttributedStringForRange: range] : nil;
2532         
2533         if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute])
2534             return [self doAXStyleRangeForIndex: number];
2535     }
2536     
2537     return nil;
2538 }
2539
2540 - (id)accessibilityHitTest:(NSPoint)point
2541 {
2542     if (!m_renderer)
2543         return NSAccessibilityUnignoredAncestor(self);
2544     
2545     HitTestRequest request(true, true);
2546     HitTestResult result = HitTestResult(IntPoint(point));
2547     m_renderer->layer()->hitTest(request, result);
2548     if (!result.innerNode())
2549         return NSAccessibilityUnignoredAncestor(self);
2550     Node* node = result.innerNode()->shadowAncestorNode();
2551     RenderObject* obj = node->renderer();
2552     if (!obj)
2553         return NSAccessibilityUnignoredAncestor(self);
2554     
2555     return NSAccessibilityUnignoredAncestor(obj->document()->axObjectCache()->get(obj));
2556 }
2557
2558 - (RenderObject*)rendererForView:(NSView*)view
2559 {
2560     // check for WebKit NSView that lets us find its bridge
2561     WebCoreFrameBridge* bridge = nil;
2562     if ([view conformsToProtocol:@protocol(WebCoreBridgeHolder)]) {
2563         NSView<WebCoreBridgeHolder>* bridgeHolder = (NSView<WebCoreBridgeHolder>*)view;
2564         bridge = [bridgeHolder webCoreBridge];
2565     }
2566
2567     Frame* frame = [bridge _frame];
2568     if (!frame)
2569         return nil;
2570         
2571     Document* document = frame->document();
2572     if (!document)
2573         return nil;
2574         
2575     Node* node = document->ownerElement();
2576     if (!node)
2577         return nil;
2578
2579     return node->renderer();
2580 }
2581
2582 // _accessibilityParentForSubview is called by AppKit when moving up the tree
2583 // we override it so that we can return our WebCoreAXObject parent of an AppKit AX object
2584 - (id)_accessibilityParentForSubview:(NSView*)subview
2585 {   
2586     RenderObject* renderer = [self rendererForView:subview];
2587     if (!renderer)
2588         return nil;
2589         
2590     WebCoreAXObject* obj = renderer->document()->axObjectCache()->get(renderer);
2591     return [obj parentObjectUnignored];
2592 }
2593
2594 - (id)accessibilityFocusedUIElement
2595 {
2596     // get the focused node in the page
2597     Page* page = m_renderer->document()->page();
2598     if (!page)
2599         return nil;
2600
2601     Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
2602     Node* focusedNode = focusedDocument->focusedNode();
2603     if (!focusedNode || !focusedNode->renderer())
2604         focusedNode = focusedDocument;
2605
2606     WebCoreAXObject* obj = focusedNode->renderer()->document()->axObjectCache()->get(focusedNode->renderer());
2607     
2608     // the HTML element, for example, is focusable but has an AX object that is ignored
2609     if ([obj accessibilityIsIgnored])
2610         obj = [obj parentObjectUnignored];
2611     
2612     return obj;
2613 }
2614
2615 - (void)doSetAXSelectedTextMarkerRange: (WebCoreTextMarkerRange*)textMarkerRange
2616 {
2617     // extract the start and end VisiblePosition
2618     VisiblePosition startVisiblePosition = [self visiblePositionForStartOfTextMarkerRange: textMarkerRange];
2619     if (startVisiblePosition.isNull())
2620         return;
2621     
2622     VisiblePosition endVisiblePosition = [self visiblePositionForEndOfTextMarkerRange: textMarkerRange];
2623     if (endVisiblePosition.isNull())
2624         return;
2625     
2626     // make selection and tell the document to use it
2627     Selection newSelection = Selection(startVisiblePosition, endVisiblePosition);
2628     m_renderer->document()->frame()->selectionController()->setSelection(newSelection);
2629 }
2630
2631 - (BOOL)canSetFocusAttribute
2632 {
2633     // NOTE: It would be more accurate to ask the document whether setFocusedNode() would 
2634     // do anything.  For example, it setFocusedNode() will do nothing if the current focused
2635     // node will not relinquish the focus.
2636     if (!m_renderer->element() || !m_renderer->element()->isEnabled())
2637         return NO;
2638         
2639     NSString* role = [self role];
2640     if ([role isEqualToString:@"AXLink"] ||
2641         [role isEqualToString:NSAccessibilityTextFieldRole] ||
2642         [role isEqualToString:NSAccessibilityTextAreaRole] ||
2643         [role isEqualToString:NSAccessibilityButtonRole] ||
2644         [role isEqualToString:NSAccessibilityPopUpButtonRole] ||
2645         [role isEqualToString:NSAccessibilityCheckBoxRole] ||
2646         [role isEqualToString:NSAccessibilityRadioButtonRole])
2647         return YES;
2648
2649     return NO;
2650 }
2651
2652 - (BOOL)canSetValueAttribute
2653 {
2654     return [self isTextControl];
2655 }
2656
2657 - (BOOL)canSetTextRangeAttributes
2658 {
2659     return [self isTextControl];
2660 }
2661
2662 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2663 {
2664     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2665         return YES;
2666         
2667     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2668         return [self canSetFocusAttribute];
2669
2670     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2671         return [self canSetValueAttribute];
2672
2673     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
2674         [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
2675         [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2676         return [self canSetTextRangeAttributes];
2677     
2678     return NO;
2679 }
2680
2681 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2682 {
2683     WebCoreTextMarkerRange* textMarkerRange = nil;
2684     NSNumber*               number = nil;
2685     NSString*               string = nil;
2686     NSRange                 range = {0, 0};
2687
2688     // decode the parameter
2689     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
2690         textMarkerRange = (WebCoreTextMarkerRange*) value;
2691
2692     else if ([value isKindOfClass:[NSNumber self]])
2693         number = value;
2694
2695     else if ([value isKindOfClass:[NSString self]])
2696         string = value;
2697     
2698     else if ([value isKindOfClass:[NSValue self]])
2699         range = [value rangeValue];
2700     
2701     // handle the command
2702     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
2703         ASSERT(textMarkerRange);
2704         [self doSetAXSelectedTextMarkerRange:textMarkerRange];
2705         
2706     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2707         ASSERT(number);
2708         if ([self canSetFocusAttribute] && number) {
2709             if ([number intValue] == 0)
2710                 m_renderer->document()->setFocusedNode(0);
2711             else {
2712                 if (m_renderer->element()->isElementNode())
2713                     static_cast<Element*>(m_renderer->element())->focus();
2714                 else
2715                     m_renderer->document()->setFocusedNode(m_renderer->element());
2716             }
2717         }
2718     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2719         if (!string)
2720             return;
2721         if (m_renderer->isTextField()) {
2722             HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
2723             input->setValue(string);
2724         } else if (m_renderer->isTextArea()) {
2725             HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element());
2726             textArea->setValue(string);
2727       }
2728     } else if ([self isTextControl]) {
2729         RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
2730         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2731             // TODO: set selected text (ReplaceSelectionCommand). <rdar://problem/4712125>
2732         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2733             textControl->setSelectionRange(range.location, range.location + range.length);
2734         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
2735             // TODO: make range visible (scrollRectToVisible).  <rdar://problem/4712101>
2736         }
2737     }
2738 }
2739
2740 - (WebCoreAXObject*)observableObject
2741 {
2742     for (RenderObject* renderer = m_renderer; renderer && renderer->element(); renderer = renderer->parent()) {
2743         if (renderer->isTextField() || renderer->isTextArea())
2744             return renderer->document()->axObjectCache()->get(renderer);
2745     }
2746     
2747     return nil;
2748 }
2749
2750 - (void)childrenChanged
2751 {
2752     [self clearChildren];
2753     
2754     if ([self accessibilityIsIgnored])
2755         [[self parentObject] childrenChanged];
2756 }
2757
2758 - (void)clearChildren
2759 {
2760     [m_children release];
2761     m_children = nil;
2762 }
2763
2764 -(AXID)axObjectID
2765 {
2766     return m_id;
2767 }
2768
2769 -(void)setAXObjectID:(AXID) axObjectID
2770 {
2771     m_id = axObjectID;
2772 }
2773
2774 - (void)removeAXObjectID
2775 {
2776     if (!m_id)
2777         return;
2778         
2779     m_renderer->document()->axObjectCache()->removeAXID(self);
2780 }
2781
2782 @end