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