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