Reviewed by Tim H.
[WebKit-https.git] / WebCore / bindings / objc / DOM.mm
1 /*
2  * Copyright (C) 2004-2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2006 James G. Speth (speth@end.com)
4  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #import "config.h"
29 #import "DOM.h"
30
31 #import "CDATASection.h"
32 #import "CSSStyleSheet.h"
33 #import "Comment.h"
34 #import "DOMHTML.h"
35 #import "DOMImplementationFront.h"
36 #import "DOMInternal.h"
37 #import "DOMPrivate.h"
38 #import "DeprecatedValueList.h"
39 #import "Document.h"
40 #import "DocumentFragment.h"
41 #import "DocumentType.h"
42 #import "EntityReference.h"
43 #import "Event.h"
44 #import "EventListener.h"
45 #import "FontData.h"
46 #import "FoundationExtras.h"
47 #import "FrameMac.h"
48 #import "HTMLDocument.h"
49 #import "HTMLNames.h"
50 #import "HTMLPlugInElement.h"
51 #import "IntRect.h"
52 #import "NodeFilter.h"
53 #import "NodeFilterCondition.h"
54 #import "NodeIterator.h"
55 #import "NodeList.h"
56 #import "ProcessingInstruction.h"
57 #import "QualifiedName.h"
58 #import "Range.h"
59 #import "RenderImage.h"
60 #import "Text.h"
61 #import "TreeWalker.h"
62 #import "WebScriptObjectPrivate.h"
63 #import "csshelper.h"
64
65 // From old DOMCore.h
66 #import "DOMObject.h"
67 #import "DOMException.h"
68
69 // Generated Objective-C Bindings
70 #import "DOMAttr.h"
71 #import "DOMCDATASection.h"
72 #import "DOMCharacterData.h"
73 #import "DOMComment.h"
74 #import "DOMDOMImplementation.h"
75 #import "DOMDocument.h"
76 #import "DOMDocumentFragment.h"
77 #import "DOMDocumentType.h"
78 #import "DOMElement.h"
79 #import "DOMEntity.h"
80 #import "DOMEntityReference.h"
81 #import "DOMNamedNodeMap.h"
82 #import "DOMNode.h"
83 #import "DOMNodeList.h"
84 #import "DOMNotation.h"
85 #import "DOMProcessingInstruction.h"
86 #import "DOMText.h"
87
88 // From old DOMHTML.h
89 #import "DOMHTMLAppletElement.h"
90 #import "DOMHTMLOptionElement.h"
91
92 // Generated Objective-C Bindings
93 #import "DOMHTMLAnchorElement.h"
94 #import "DOMHTMLAreaElement.h"
95 #import "DOMHTMLBRElement.h"
96 #import "DOMHTMLBaseElement.h"
97 #import "DOMHTMLBaseFontElement.h"
98 #import "DOMHTMLBodyElement.h"
99 #import "DOMHTMLButtonElement.h"
100 #import "DOMHTMLCollection.h"
101 #import "DOMHTMLDListElement.h"
102 #import "DOMHTMLDirectoryElement.h"
103 #import "DOMHTMLDivElement.h"
104 #import "DOMHTMLDocument.h"
105 #import "DOMHTMLElement.h"
106 #import "DOMHTMLFieldSetElement.h"
107 #import "DOMHTMLFontElement.h"
108 #import "DOMHTMLFormElement.h"
109 #import "DOMHTMLFrameElement.h"
110 #import "DOMHTMLFrameSetElement.h"
111 #import "DOMHTMLHRElement.h"
112 #import "DOMHTMLHeadElement.h"
113 #import "DOMHTMLHeadingElement.h"
114 #import "DOMHTMLHtmlElement.h"
115 #import "DOMHTMLIFrameElement.h"
116 #import "DOMHTMLImageElement.h"
117 #import "DOMHTMLInputElement.h"
118 #import "DOMHTMLIsIndexElement.h"
119 #import "DOMHTMLLIElement.h"
120 #import "DOMHTMLLabelElement.h"
121 #import "DOMHTMLLegendElement.h"
122 #import "DOMHTMLLinkElement.h"
123 #import "DOMHTMLMapElement.h"
124 #import "DOMHTMLMenuElement.h"
125 #import "DOMHTMLMetaElement.h"
126 #import "DOMHTMLModElement.h"
127 #import "DOMHTMLOListElement.h"
128 #import "DOMHTMLObjectElement.h"
129 #import "DOMHTMLOptGroupElement.h"
130 #import "DOMHTMLOptionsCollection.h"
131 #import "DOMHTMLParagraphElement.h"
132 #import "DOMHTMLParamElement.h"
133 #import "DOMHTMLPreElement.h"
134 #import "DOMHTMLQuoteElement.h"
135 #import "DOMHTMLScriptElement.h"
136 #import "DOMHTMLSelectElement.h"
137 #import "DOMHTMLStyleElement.h"
138 #import "DOMHTMLTableCaptionElement.h"
139 #import "DOMHTMLTableCellElement.h"
140 #import "DOMHTMLTableColElement.h"
141 #import "DOMHTMLTableElement.h"
142 #import "DOMHTMLTableRowElement.h"
143 #import "DOMHTMLTableSectionElement.h"
144 #import "DOMHTMLTextAreaElement.h"
145 #import "DOMHTMLTitleElement.h"
146 #import "DOMHTMLUListElement.h"
147
148 #import <objc/objc-class.h>
149
150 using namespace WebCore::HTMLNames;
151
152 class ObjCEventListener : public WebCore::EventListener {
153 public:
154     static ObjCEventListener* find(id <DOMEventListener>);
155     static ObjCEventListener* create(id <DOMEventListener>);
156
157 private:
158     ObjCEventListener(id <DOMEventListener>);
159     virtual ~ObjCEventListener();
160
161     virtual void handleEvent(WebCore::Event*, bool isWindowEvent);
162
163     id <DOMEventListener> m_listener;
164 };
165
166 typedef HashMap<id, ObjCEventListener*> ListenerMap;
167 typedef HashMap<WebCore::AtomicStringImpl*, Class> ObjCClassMap;
168
169 static ObjCClassMap* elementClassMap;
170 static ListenerMap* listenerMap;
171
172
173 //------------------------------------------------------------------------------------------
174 // DOMNode
175
176 static void addElementClass(const WebCore::QualifiedName& tag, Class objCClass)
177 {
178     elementClassMap->set(tag.localName().impl(), objCClass);
179 }
180
181 static void createHTMLElementClassMap()
182 {
183     // Create the table.
184     elementClassMap = new ObjCClassMap;
185     
186     // Populate it with HTML element classes.
187     addElementClass(aTag, [DOMHTMLAnchorElement class]);
188     addElementClass(appletTag, [DOMHTMLAppletElement class]);
189     addElementClass(areaTag, [DOMHTMLAreaElement class]);
190     addElementClass(baseTag, [DOMHTMLBaseElement class]);
191     addElementClass(basefontTag, [DOMHTMLBaseFontElement class]);
192     addElementClass(bodyTag, [DOMHTMLBodyElement class]);
193     addElementClass(brTag, [DOMHTMLBRElement class]);
194     addElementClass(buttonTag, [DOMHTMLButtonElement class]);
195     addElementClass(canvasTag, [DOMHTMLImageElement class]);
196     addElementClass(captionTag, [DOMHTMLTableCaptionElement class]);
197     addElementClass(colTag, [DOMHTMLTableColElement class]);
198     addElementClass(colgroupTag, [DOMHTMLTableColElement class]);
199     addElementClass(dirTag, [DOMHTMLDirectoryElement class]);
200     addElementClass(divTag, [DOMHTMLDivElement class]);
201     addElementClass(dlTag, [DOMHTMLDListElement class]);
202     addElementClass(fieldsetTag, [DOMHTMLFieldSetElement class]);
203     addElementClass(fontTag, [DOMHTMLFontElement class]);
204     addElementClass(formTag, [DOMHTMLFormElement class]);
205     addElementClass(frameTag, [DOMHTMLFrameElement class]);
206     addElementClass(framesetTag, [DOMHTMLFrameSetElement class]);
207     addElementClass(h1Tag, [DOMHTMLHeadingElement class]);
208     addElementClass(h2Tag, [DOMHTMLHeadingElement class]);
209     addElementClass(h3Tag, [DOMHTMLHeadingElement class]);
210     addElementClass(h4Tag, [DOMHTMLHeadingElement class]);
211     addElementClass(h5Tag, [DOMHTMLHeadingElement class]);
212     addElementClass(h6Tag, [DOMHTMLHeadingElement class]);
213     addElementClass(headTag, [DOMHTMLHeadElement class]);
214     addElementClass(hrTag, [DOMHTMLHRElement class]);
215     addElementClass(htmlTag, [DOMHTMLHtmlElement class]);
216     addElementClass(iframeTag, [DOMHTMLIFrameElement class]);
217     addElementClass(imgTag, [DOMHTMLImageElement class]);
218     addElementClass(inputTag, [DOMHTMLInputElement class]);
219     addElementClass(isindexTag, [DOMHTMLIsIndexElement class]);
220     addElementClass(labelTag, [DOMHTMLLabelElement class]);
221     addElementClass(legendTag, [DOMHTMLLegendElement class]);
222     addElementClass(liTag, [DOMHTMLLIElement class]);
223     addElementClass(linkTag, [DOMHTMLLinkElement class]);
224     addElementClass(listingTag, [DOMHTMLPreElement class]);
225     addElementClass(mapTag, [DOMHTMLMapElement class]);
226     addElementClass(menuTag, [DOMHTMLMenuElement class]);
227     addElementClass(metaTag, [DOMHTMLMetaElement class]);
228     addElementClass(objectTag, [DOMHTMLObjectElement class]);
229     addElementClass(olTag, [DOMHTMLOListElement class]);
230     addElementClass(optgroupTag, [DOMHTMLOptGroupElement class]);
231     addElementClass(optionTag, [DOMHTMLOptionElement class]);
232     addElementClass(pTag, [DOMHTMLParagraphElement class]);
233     addElementClass(paramTag, [DOMHTMLParamElement class]);
234     addElementClass(preTag, [DOMHTMLPreElement class]);
235     addElementClass(qTag, [DOMHTMLQuoteElement class]);
236     addElementClass(scriptTag, [DOMHTMLScriptElement class]);
237     addElementClass(selectTag, [DOMHTMLSelectElement class]);
238     addElementClass(styleTag, [DOMHTMLStyleElement class]);
239     addElementClass(tableTag, [DOMHTMLTableElement class]);
240     addElementClass(tbodyTag, [DOMHTMLTableSectionElement class]);
241     addElementClass(tdTag, [DOMHTMLTableCellElement class]);
242     addElementClass(textareaTag, [DOMHTMLTextAreaElement class]);
243     addElementClass(tfootTag, [DOMHTMLTableSectionElement class]);
244     addElementClass(theadTag, [DOMHTMLTableSectionElement class]);
245     addElementClass(titleTag, [DOMHTMLTitleElement class]);
246     addElementClass(trTag, [DOMHTMLTableRowElement class]);
247     addElementClass(ulTag, [DOMHTMLUListElement class]);
248
249     // FIXME: Reflect marquee once the API has been determined.
250 }
251
252 static Class elementClass(const WebCore::AtomicString& tagName)
253 {
254     if (!elementClassMap)
255         createHTMLElementClassMap();
256     Class objcClass = elementClassMap->get(tagName.impl());
257     if (!objcClass)
258         objcClass = [DOMHTMLElement class];
259     return objcClass;
260 }
261
262 @implementation DOMNode (WebCoreInternal)
263
264 // FIXME: should this go in the main implementation?
265 - (NSString *)description
266 {
267     if (!_internal)
268         return [NSString stringWithFormat:@"<%@: null>", [[self class] description], self];
269     
270     NSString *value = [self nodeValue];
271     if (value)
272         return [NSString stringWithFormat:@"<%@ [%@]: %p '%@'>",
273             [[self class] description], [self nodeName], _internal, value];
274
275     return [NSString stringWithFormat:@"<%@ [%@]: %p>", [[self class] description], [self nodeName], _internal];
276 }
277
278 - (id)_initWithNode:(WebCore::Node *)impl
279 {
280     ASSERT(impl);
281
282     [super _init];
283     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
284     impl->ref();
285     addDOMWrapper(self, impl);
286     return self;
287 }
288
289 + (DOMNode *)_nodeWith:(WebCore::Node *)impl
290 {
291     if (!impl)
292         return nil;
293     
294     id cachedInstance;
295     cachedInstance = getDOMWrapper(impl);
296     if (cachedInstance)
297         return [[cachedInstance retain] autorelease];
298     
299     Class wrapperClass = nil;
300     switch (impl->nodeType()) {
301         case WebCore::Node::ELEMENT_NODE:
302             if (impl->isHTMLElement())
303                 wrapperClass = elementClass(static_cast<WebCore::HTMLElement*>(impl)->localName());
304             else
305                 wrapperClass = [DOMElement class];
306             break;
307         case WebCore::Node::ATTRIBUTE_NODE:
308             wrapperClass = [DOMAttr class];
309             break;
310         case WebCore::Node::TEXT_NODE:
311             wrapperClass = [DOMText class];
312             break;
313         case WebCore::Node::CDATA_SECTION_NODE:
314             wrapperClass = [DOMCDATASection class];
315             break;
316         case WebCore::Node::ENTITY_REFERENCE_NODE:
317             wrapperClass = [DOMEntityReference class];
318             break;
319         case WebCore::Node::ENTITY_NODE:
320             wrapperClass = [DOMEntity class];
321             break;
322         case WebCore::Node::PROCESSING_INSTRUCTION_NODE:
323             wrapperClass = [DOMProcessingInstruction class];
324             break;
325         case WebCore::Node::COMMENT_NODE:
326             wrapperClass = [DOMComment class];
327             break;
328         case WebCore::Node::DOCUMENT_NODE:
329             if (static_cast<WebCore::Document*>(impl)->isHTMLDocument())
330                 wrapperClass = [DOMHTMLDocument class];
331             else
332                 wrapperClass = [DOMDocument class];
333             break;
334         case WebCore::Node::DOCUMENT_TYPE_NODE:
335             wrapperClass = [DOMDocumentType class];
336             break;
337         case WebCore::Node::DOCUMENT_FRAGMENT_NODE:
338             wrapperClass = [DOMDocumentFragment class];
339             break;
340         case WebCore::Node::NOTATION_NODE:
341             wrapperClass = [DOMNotation class];
342             break;
343         case WebCore::Node::XPATH_NAMESPACE_NODE:
344             // FIXME: Create an XPath objective C wrapper
345             // See http://bugzilla.opendarwin.org/show_bug.cgi?id=8755
346             return nil;
347     }
348     return [[[wrapperClass alloc] _initWithNode:impl] autorelease];
349 }
350
351 - (WebCore::Node *)_node
352 {
353     return reinterpret_cast<WebCore::Node*>(_internal);
354 }
355
356 - (const KJS::Bindings::RootObject *)_executionContext
357 {
358     if (WebCore::Node *n = [self _node]) {
359         if (WebCore::FrameMac *f = Mac(n->document()->frame()))
360             return f->executionContextForDOM();
361     }
362     return 0;
363 }
364
365 @end
366
367 @implementation DOMNode (DOMNodeExtensions)
368
369 // FIXME: this should be implemented in the implementation
370 - (NSRect)boundingBox
371 {
372     WebCore::RenderObject *renderer = [self _node]->renderer();
373     if (renderer)
374         return renderer->absoluteBoundingBoxRect();
375     return NSZeroRect;
376 }
377
378 // FIXME: this should be implemented in the implementation
379 - (NSArray *)lineBoxRects
380 {
381     WebCore::RenderObject *renderer = [self _node]->renderer();
382     if (renderer) {
383         Vector<WebCore::IntRect> rects;
384         renderer->lineBoxRects(rects);
385         size_t size = rects.size();
386         NSMutableArray *results = [NSMutableArray arrayWithCapacity:size];
387         for (size_t i = 0; i < size; ++i)
388             [results addObject:[NSValue valueWithRect:rects[i]]];
389         return results;
390     }
391     return nil;
392 }
393
394 @end
395
396 // FIXME: this should be auto-generated
397 @implementation DOMNode (DOMEventTarget)
398
399 - (void)addEventListener:(NSString *)type listener:(id <DOMEventListener>)listener useCapture:(BOOL)useCapture
400 {
401     if (![self _node]->isEventTargetNode())
402         raiseDOMException(DOM_NOT_SUPPORTED_ERR);
403     
404     WebCore::EventListener *wrapper = ObjCEventListener::create(listener);
405     EventTargetNodeCast([self _node])->addEventListener(type, wrapper, useCapture);
406     wrapper->deref();
407 }
408
409 - (void)addEventListener:(NSString *)type :(id <DOMEventListener>)listener :(BOOL)useCapture
410 {
411     // FIXME: this method can be removed once Mail changes to use the new method <rdar://problem/4746649>
412     [self addEventListener:type listener:listener useCapture:useCapture];
413 }
414
415 - (void)removeEventListener:(NSString *)type listener:(id <DOMEventListener>)listener useCapture:(BOOL)useCapture
416 {
417     if (![self _node]->isEventTargetNode())
418         raiseDOMException(DOM_NOT_SUPPORTED_ERR);
419
420     if (WebCore::EventListener *wrapper = ObjCEventListener::find(listener))
421         EventTargetNodeCast([self _node])->removeEventListener(type, wrapper, useCapture);
422 }
423
424 - (void)removeEventListener:(NSString *)type :(id <DOMEventListener>)listener :(BOOL)useCapture
425 {
426     // FIXME: this method can be removed once Mail changes to use the new method <rdar://problem/4746649>
427     [self removeEventListener:type listener:listener useCapture:useCapture];
428 }
429
430 - (BOOL)dispatchEvent:(DOMEvent *)event
431 {
432     if (![self _node]->isEventTargetNode())
433         raiseDOMException(DOM_NOT_SUPPORTED_ERR);
434
435     WebCore::ExceptionCode ec = 0;
436     BOOL result = EventTargetNodeCast([self _node])->dispatchEvent([event _event], ec);
437     raiseOnDOMError(ec);
438     return result;
439 }
440
441 @end
442
443 //------------------------------------------------------------------------------------------
444 // DOMElement
445
446 // FIXME: this should be auto-genenerate in DOMElement.mm
447 @implementation DOMElement (DOMElementAppKitExtensions)
448
449 // FIXME: this should be implemented in the implementation
450 - (NSImage*)image
451 {
452     WebCore::RenderObject* renderer = [self _element]->renderer();
453     if (renderer && renderer->isImage()) {
454         WebCore::RenderImage* img = static_cast<WebCore::RenderImage*>(renderer);
455         if (img->cachedImage() && !img->cachedImage()->isErrorImage())
456             return img->cachedImage()->image()->getNSImage();
457     }
458     return nil;
459 }
460
461 @end
462
463 @implementation DOMElement (WebPrivate)
464
465 // FIXME: this should be implemented in the implementation
466 - (NSFont *)_font
467 {
468     WebCore::RenderObject* renderer = [self _element]->renderer();
469     if (renderer)
470         return renderer->style()->font().primaryFont()->getNSFont();
471     return nil;
472 }
473
474 // FIXME: this should be implemented in the implementation
475 - (NSData*)_imageTIFFRepresentation
476 {
477     WebCore::RenderObject* renderer = [self _element]->renderer();
478     if (renderer && renderer->isImage()) {
479         WebCore::RenderImage* img = static_cast<WebCore::RenderImage*>(renderer);
480         if (img->cachedImage() && !img->cachedImage()->isErrorImage())
481             return (NSData*)(img->cachedImage()->image()->getTIFFRepresentation());
482     }
483     return nil;
484 }
485
486 // FIXME: this should be implemented in the implementation
487 - (NSURL *)_getURLAttribute:(NSString *)name
488 {
489     ASSERT(name);
490     WebCore::Element* element = [self _element];
491     ASSERT(element);
492     return WebCore::KURL(element->document()->completeURL(parseURL(element->getAttribute(name)).deprecatedString())).getNSURL();
493 }
494
495 // FIXME: this should be implemented in the implementation
496 - (void *)_NPObject
497 {
498     WebCore::Element* element = [self _element];
499     if (element->hasTagName(appletTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag))
500         return static_cast<WebCore::HTMLPlugInElement*>(element)->getNPObject();
501     return 0;
502 }
503
504 // FIXME: this should be implemented in the implementation
505 - (BOOL)isFocused
506 {
507     WebCore::Element* impl = [self _element];
508     if (impl->document()->focusNode() == impl)
509         return YES;
510     return NO;
511 }
512
513 @end
514
515
516 //------------------------------------------------------------------------------------------
517 // DOMRange
518
519 @implementation DOMRange
520
521 - (void)dealloc
522 {
523     if (_internal)
524         reinterpret_cast<WebCore::Range*>(_internal)->deref();
525     [super dealloc];
526 }
527
528 - (void)finalize
529 {
530     if (_internal)
531         reinterpret_cast<WebCore::Range*>(_internal)->deref();
532     [super finalize];
533 }
534
535 - (NSString *)description
536 {
537     if (!_internal)
538         return @"<DOMRange: null>";
539     return [NSString stringWithFormat:@"<DOMRange: %@ %d %@ %d>",
540                [self startContainer], [self startOffset], [self endContainer], [self endOffset]];
541 }
542
543 - (DOMNode *)startContainer
544 {
545     WebCore::ExceptionCode ec = 0;
546     DOMNode *result = [DOMNode _nodeWith:[self _range]->startContainer(ec)];
547     raiseOnDOMError(ec);
548     return result;
549 }
550
551 - (int)startOffset
552 {
553     WebCore::ExceptionCode ec = 0;
554     int result = [self _range]->startOffset(ec);
555     raiseOnDOMError(ec);
556     return result;
557 }
558
559 - (DOMNode *)endContainer
560 {
561     WebCore::ExceptionCode ec = 0;
562     DOMNode *result = [DOMNode _nodeWith:[self _range]->endContainer(ec)];
563     raiseOnDOMError(ec);
564     return result;
565 }
566
567 - (int)endOffset
568 {
569     WebCore::ExceptionCode ec = 0;
570     int result = [self _range]->endOffset(ec);
571     raiseOnDOMError(ec);
572     return result;
573 }
574
575 - (BOOL)collapsed
576 {
577     WebCore::ExceptionCode ec = 0;
578     BOOL result = [self _range]->collapsed(ec);
579     raiseOnDOMError(ec);
580     return result;
581 }
582
583 - (DOMNode *)commonAncestorContainer
584 {
585     WebCore::ExceptionCode ec = 0;
586     DOMNode *result = [DOMNode _nodeWith:[self _range]->commonAncestorContainer(ec)];
587     raiseOnDOMError(ec);
588     return result;
589 }
590
591 - (void)setStart:(DOMNode *)refNode :(int)offset
592 {
593     WebCore::ExceptionCode ec = 0;
594     [self _range]->setStart([refNode _node], offset, ec);
595     raiseOnDOMError(ec);
596 }
597
598 - (void)setEnd:(DOMNode *)refNode :(int)offset
599 {
600     WebCore::ExceptionCode ec = 0;
601     [self _range]->setEnd([refNode _node], offset, ec);
602     raiseOnDOMError(ec);
603 }
604
605 - (void)setStartBefore:(DOMNode *)refNode
606 {
607     WebCore::ExceptionCode ec = 0;
608     [self _range]->setStartBefore([refNode _node], ec);
609     raiseOnDOMError(ec);
610 }
611
612 - (void)setStartAfter:(DOMNode *)refNode
613 {
614     WebCore::ExceptionCode ec = 0;
615     [self _range]->setStartAfter([refNode _node], ec);
616     raiseOnDOMError(ec);
617 }
618
619 - (void)setEndBefore:(DOMNode *)refNode
620 {
621     WebCore::ExceptionCode ec = 0;
622     [self _range]->setEndBefore([refNode _node], ec);
623     raiseOnDOMError(ec);
624 }
625
626 - (void)setEndAfter:(DOMNode *)refNode
627 {
628     WebCore::ExceptionCode ec = 0;
629     [self _range]->setEndAfter([refNode _node], ec);
630     raiseOnDOMError(ec);
631 }
632
633 - (void)collapse:(BOOL)toStart
634 {
635     WebCore::ExceptionCode ec = 0;
636     [self _range]->collapse(toStart, ec);
637     raiseOnDOMError(ec);
638 }
639
640 - (void)selectNode:(DOMNode *)refNode
641 {
642     WebCore::ExceptionCode ec = 0;
643     [self _range]->selectNode([refNode _node], ec);
644     raiseOnDOMError(ec);
645 }
646
647 - (void)selectNodeContents:(DOMNode *)refNode
648 {
649     WebCore::ExceptionCode ec = 0;
650     [self _range]->selectNodeContents([refNode _node], ec);
651     raiseOnDOMError(ec);
652 }
653
654 - (short)compareBoundaryPoints:(unsigned short)how :(DOMRange *)sourceRange
655 {
656     WebCore::ExceptionCode ec = 0;
657     short result = [self _range]->compareBoundaryPoints(static_cast<WebCore::Range::CompareHow>(how), [sourceRange _range], ec);
658     raiseOnDOMError(ec);
659     return result;
660 }
661
662 - (void)deleteContents
663 {
664     WebCore::ExceptionCode ec = 0;
665     [self _range]->deleteContents(ec);
666     raiseOnDOMError(ec);
667 }
668
669 - (DOMDocumentFragment *)extractContents
670 {
671     WebCore::ExceptionCode ec = 0;
672     DOMDocumentFragment *result = [DOMDocumentFragment _documentFragmentWith:[self _range]->extractContents(ec).get()];
673     raiseOnDOMError(ec);
674     return result;
675 }
676
677 - (DOMDocumentFragment *)cloneContents
678 {
679     WebCore::ExceptionCode ec = 0;
680     DOMDocumentFragment *result = [DOMDocumentFragment _documentFragmentWith:[self _range]->cloneContents(ec).get()];
681     raiseOnDOMError(ec);
682     return result;
683 }
684
685 - (void)insertNode:(DOMNode *)newNode
686 {
687     WebCore::ExceptionCode ec = 0;
688     [self _range]->insertNode([newNode _node], ec);
689     raiseOnDOMError(ec);
690 }
691
692 - (void)surroundContents:(DOMNode *)newParent
693 {
694     WebCore::ExceptionCode ec = 0;
695     [self _range]->surroundContents([newParent _node], ec);
696     raiseOnDOMError(ec);
697 }
698
699 - (DOMRange *)cloneRange
700 {
701     WebCore::ExceptionCode ec = 0;
702     DOMRange *result = [DOMRange _rangeWith:[self _range]->cloneRange(ec).get()];
703     raiseOnDOMError(ec);
704     return result;
705 }
706
707 - (NSString *)toString
708 {
709     WebCore::ExceptionCode ec = 0;
710     NSString *result = [self _range]->toString(ec);
711     raiseOnDOMError(ec);
712     return result;
713 }
714
715 - (NSString *)text
716 {
717     return [self _range]->text();
718 }
719
720 - (void)detach
721 {
722     WebCore::ExceptionCode ec = 0;
723     [self _range]->detach(ec);
724     raiseOnDOMError(ec);
725 }
726
727 @end
728
729 @implementation DOMRange (WebCoreInternal)
730
731 - (id)_initWithRange:(WebCore::Range *)impl
732 {
733     ASSERT(impl);
734
735     [super _init];
736     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
737     impl->ref();
738     addDOMWrapper(self, impl);
739     return self;
740 }
741
742 + (DOMRange *)_rangeWith:(WebCore::Range *)impl
743 {
744     if (!impl)
745         return nil;
746     
747     id cachedInstance;
748     cachedInstance = getDOMWrapper(impl);
749     if (cachedInstance)
750         return [[cachedInstance retain] autorelease];
751     
752     return [[[self alloc] _initWithRange:impl] autorelease];
753 }
754
755 - (WebCore::Range *)_range
756 {
757     return reinterpret_cast<WebCore::Range*>(_internal);
758 }
759
760 @end
761
762 @implementation DOMRange (WebPrivate)
763
764 - (NSString *)_text
765 {
766     return [self text];
767 }
768
769 @end
770
771
772 //------------------------------------------------------------------------------------------
773 // DOMNodeFilter
774
775 @implementation DOMNodeFilter
776
777 - (id)_initWithNodeFilter:(WebCore::NodeFilter *)impl
778 {
779     ASSERT(impl);
780
781     [super _init];
782     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
783     impl->ref();
784     addDOMWrapper(self, impl);
785     return self;
786 }
787
788 + (DOMNodeFilter *)_nodeFilterWith:(WebCore::NodeFilter *)impl
789 {
790     if (!impl)
791         return nil;
792     
793     id cachedInstance;
794     cachedInstance = getDOMWrapper(impl);
795     if (cachedInstance)
796         return [[cachedInstance retain] autorelease];
797     
798     return [[[self alloc] _initWithNodeFilter:impl] autorelease];
799 }
800
801 - (WebCore::NodeFilter *)_nodeFilter
802 {
803     return reinterpret_cast<WebCore::NodeFilter*>(_internal);
804 }
805
806 - (void)dealloc
807 {
808     if (_internal)
809         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
810     [super dealloc];
811 }
812
813 - (void)finalize
814 {
815     if (_internal)
816         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
817     [super finalize];
818 }
819
820 - (short)acceptNode:(DOMNode *)node
821 {
822     return [self _nodeFilter]->acceptNode([node _node]);
823 }
824
825 @end
826
827
828 //------------------------------------------------------------------------------------------
829 // DOMNodeIterator
830
831 @implementation DOMNodeIterator(WebCoreInternal)
832
833 - (id)_initWithNodeIterator:(WebCore::NodeIterator *)impl filter:(id <DOMNodeFilter>)filter
834 {
835     ASSERT(impl);
836
837     [super _init];
838     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
839     impl->ref();
840     addDOMWrapper(self, impl);
841     m_filter = [filter retain];
842     return self;
843 }
844
845 - (WebCore::NodeIterator *)_nodeIterator
846 {
847     return reinterpret_cast<WebCore::NodeIterator*>(_internal);
848 }
849
850 + (DOMNodeIterator *)_nodeIteratorWith:(WebCore::NodeIterator *)impl filter:(id <DOMNodeFilter>)filter
851 {
852     if (!impl)
853         return nil;
854     
855     id cachedInstance;
856     cachedInstance = getDOMWrapper(impl);
857     if (cachedInstance)
858         return [[cachedInstance retain] autorelease];
859     
860     return [[[self alloc] _initWithNodeIterator:impl filter:filter] autorelease];
861 }
862
863 @end
864
865
866 //------------------------------------------------------------------------------------------
867 // DOMTreeWalker
868
869 @implementation DOMTreeWalker (WebCoreInternal)
870
871 - (id)_initWithTreeWalker:(WebCore::TreeWalker *)impl filter:(id <DOMNodeFilter>)filter
872 {
873     ASSERT(impl);
874
875     [super _init];
876     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
877     impl->ref();
878     addDOMWrapper(self, impl);
879     m_filter = [filter retain];
880     return self;
881 }
882
883 - (WebCore::TreeWalker *)_treeWalker
884 {
885     return reinterpret_cast<WebCore::TreeWalker *>(_internal);
886 }
887
888 + (DOMTreeWalker *)_treeWalkerWith:(WebCore::TreeWalker *)impl filter:(id <DOMNodeFilter>)filter
889 {
890     if (!impl)
891         return nil;
892     
893     id cachedInstance;
894     cachedInstance = getDOMWrapper(impl);
895     if (cachedInstance)
896         return [[cachedInstance retain] autorelease];
897     
898     return [[[self alloc] _initWithTreeWalker:impl filter:filter] autorelease];
899 }
900
901 @end
902
903
904 //------------------------------------------------------------------------------------------
905 // ObjCNodeFilterCondition
906
907 class ObjCNodeFilterCondition : public WebCore::NodeFilterCondition {
908 public:
909     ObjCNodeFilterCondition(id <DOMNodeFilter>);
910     virtual ~ObjCNodeFilterCondition();
911     virtual short acceptNode(WebCore::Node*) const;
912
913 private:
914     ObjCNodeFilterCondition(const ObjCNodeFilterCondition&);
915     ObjCNodeFilterCondition &operator=(const ObjCNodeFilterCondition&);
916
917     id <DOMNodeFilter> m_filter;
918 };
919
920 ObjCNodeFilterCondition::ObjCNodeFilterCondition(id <DOMNodeFilter> filter)
921     : m_filter(filter)
922 {
923     ASSERT(m_filter);
924     CFRetain(m_filter);
925 }
926
927 ObjCNodeFilterCondition::~ObjCNodeFilterCondition()
928 {
929     CFRelease(m_filter);
930 }
931
932 short ObjCNodeFilterCondition::acceptNode(WebCore::Node* node) const
933 {
934     if (!node)
935         return WebCore::NodeFilter::FILTER_REJECT;
936     return [m_filter acceptNode:[DOMNode _nodeWith:node]];
937 }
938
939
940 //------------------------------------------------------------------------------------------
941 // DOMDocument (DOMDocumentTraversal)
942
943 // FIXME: this should be auto-genenerate in DOMDocument.mm
944 @implementation DOMDocument (DOMDocumentTraversal)
945
946 - (DOMNodeIterator *)createNodeIterator:(DOMNode *)root :(unsigned)whatToShow :(id <DOMNodeFilter>)filter :(BOOL)expandEntityReferences
947 {
948     RefPtr<WebCore::NodeFilter> cppFilter;
949     if (filter)
950         cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter));
951     WebCore::ExceptionCode ec = 0;
952     RefPtr<WebCore::NodeIterator> impl = [self _document]->createNodeIterator([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
953     raiseOnDOMError(ec);
954     return [DOMNodeIterator _nodeIteratorWith:impl.get() filter:filter];
955 }
956
957 - (DOMTreeWalker *)createTreeWalker:(DOMNode *)root :(unsigned)whatToShow :(id <DOMNodeFilter>)filter :(BOOL)expandEntityReferences
958 {
959     RefPtr<WebCore::NodeFilter> cppFilter;
960     if (filter)
961         cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter));
962     WebCore::ExceptionCode ec = 0;
963     RefPtr<WebCore::TreeWalker> impl = [self _document]->createTreeWalker([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
964     raiseOnDOMError(ec);
965     return [DOMTreeWalker _treeWalkerWith:impl.get() filter:filter];
966 }
967
968 @end
969
970
971 //------------------------------------------------------------------------------------------
972 // ObjCEventListener
973
974 ObjCEventListener* ObjCEventListener::find(id <DOMEventListener> listener)
975 {
976     if (ListenerMap* map = listenerMap)
977         return map->get(listener);
978     return 0;
979 }
980
981 ObjCEventListener *ObjCEventListener::create(id <DOMEventListener> listener)
982 {
983     ObjCEventListener* wrapper = find(listener);
984     if (!wrapper)
985         wrapper = new ObjCEventListener(listener);
986     wrapper->ref();
987     return wrapper;
988 }
989
990 ObjCEventListener::ObjCEventListener(id <DOMEventListener> listener)
991     : m_listener([listener retain])
992 {
993     ListenerMap* map = listenerMap;
994     if (!map) {
995         map = new ListenerMap;
996         listenerMap = map;
997     }
998     map->set(listener, this);
999 }
1000
1001 ObjCEventListener::~ObjCEventListener()
1002 {
1003     listenerMap->remove(m_listener);
1004     [m_listener release];
1005 }
1006
1007 void ObjCEventListener::handleEvent(WebCore::Event* event, bool)
1008 {
1009     [m_listener handleEvent:[DOMEvent _eventWith:event]];
1010 }