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