2007-10-22 Eric Seidel <eric@webkit.org>
[WebKit-https.git] / WebCore / bindings / objc / DOM.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007 Apple 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 "CSSHelper.h"
33 #import "CSSStyleSheet.h"
34 #import "Comment.h"
35 #import "DOMHTMLCanvasElement.h"
36 #import "DOMInternal.h"
37 #import "DOMPrivate.h"
38 #import "Document.h"
39 #import "DocumentFragment.h"
40 #import "DocumentType.h"
41 #import "EntityReference.h"
42 #import "Event.h"
43 #import "EventListener.h"
44 #import "EventTarget.h"
45 #import "ExceptionHandlers.h"
46 #import "FontData.h"
47 #import "FoundationExtras.h"
48 #import "Frame.h"
49 #import "FrameView.h"
50 #import "HTMLDocument.h"
51 #import "HTMLNames.h"
52 #import "HTMLPlugInElement.h"
53 #import "Image.h"
54 #import "IntRect.h"
55 #import "NodeFilter.h"
56 #import "NodeFilterCondition.h"
57 #import "NodeIterator.h"
58 #import "NodeList.h"
59 #import "ProcessingInstruction.h"
60 #import "QualifiedName.h"
61 #import "Range.h"
62 #import "RenderImage.h"
63 #import "RenderView.h"
64 #import "Text.h"
65 #import "TreeWalker.h"
66 #import "WebScriptObjectPrivate.h"
67 #import <objc/objc-class.h>
68 #import <wtf/HashMap.h>
69
70 #if ENABLE(SVG)
71 #import "SVGDocument.h"
72 #import "SVGElement.h"
73 #import "SVGNames.h"
74 #import "DOMSVG.h"
75 #endif
76
77 namespace WebCore {
78
79 class ObjCEventListener : public EventListener {
80 public:
81     static ObjCEventListener* find(id <DOMEventListener>);
82     static ObjCEventListener* create(id <DOMEventListener>);
83
84 private:
85     ObjCEventListener(id <DOMEventListener>);
86     virtual ~ObjCEventListener();
87
88     virtual void handleEvent(Event*, bool isWindowEvent);
89
90     id <DOMEventListener> m_listener;
91 };
92
93 typedef HashMap<id, ObjCEventListener*> ListenerMap;
94 static ListenerMap* listenerMap;
95
96 } // namespace WebCore
97
98
99 //------------------------------------------------------------------------------------------
100 // DOMNode
101
102 namespace WebCore {
103
104 typedef HashMap<const QualifiedName::QualifiedNameImpl*, Class> ObjCClassMap;
105 static ObjCClassMap* elementClassMap;
106
107 static void addElementClass(const QualifiedName& tag, Class objCClass)
108 {
109     elementClassMap->set(tag.impl(), objCClass);
110 }
111
112 static void createElementClassMap()
113 {
114     // Create the table.
115     elementClassMap = new ObjCClassMap;
116
117     // FIXME: Reflect marquee once the API has been determined.
118
119     // Populate it with HTML and SVG element classes.
120     addElementClass(HTMLNames::aTag, [DOMHTMLAnchorElement class]);
121     addElementClass(HTMLNames::appletTag, [DOMHTMLAppletElement class]);
122     addElementClass(HTMLNames::areaTag, [DOMHTMLAreaElement class]);
123     addElementClass(HTMLNames::baseTag, [DOMHTMLBaseElement class]);
124     addElementClass(HTMLNames::basefontTag, [DOMHTMLBaseFontElement class]);
125     addElementClass(HTMLNames::bodyTag, [DOMHTMLBodyElement class]);
126     addElementClass(HTMLNames::brTag, [DOMHTMLBRElement class]);
127     addElementClass(HTMLNames::buttonTag, [DOMHTMLButtonElement class]);
128     addElementClass(HTMLNames::canvasTag, [DOMHTMLCanvasElement class]);
129     addElementClass(HTMLNames::captionTag, [DOMHTMLTableCaptionElement class]);
130     addElementClass(HTMLNames::colTag, [DOMHTMLTableColElement class]);
131     addElementClass(HTMLNames::colgroupTag, [DOMHTMLTableColElement class]);
132     addElementClass(HTMLNames::delTag, [DOMHTMLModElement class]);
133     addElementClass(HTMLNames::dirTag, [DOMHTMLDirectoryElement class]);
134     addElementClass(HTMLNames::divTag, [DOMHTMLDivElement class]);
135     addElementClass(HTMLNames::dlTag, [DOMHTMLDListElement class]);
136     addElementClass(HTMLNames::embedTag, [DOMHTMLEmbedElement class]);
137     addElementClass(HTMLNames::fieldsetTag, [DOMHTMLFieldSetElement class]);
138     addElementClass(HTMLNames::fontTag, [DOMHTMLFontElement class]);
139     addElementClass(HTMLNames::formTag, [DOMHTMLFormElement class]);
140     addElementClass(HTMLNames::frameTag, [DOMHTMLFrameElement class]);
141     addElementClass(HTMLNames::framesetTag, [DOMHTMLFrameSetElement class]);
142     addElementClass(HTMLNames::h1Tag, [DOMHTMLHeadingElement class]);
143     addElementClass(HTMLNames::h2Tag, [DOMHTMLHeadingElement class]);
144     addElementClass(HTMLNames::h3Tag, [DOMHTMLHeadingElement class]);
145     addElementClass(HTMLNames::h4Tag, [DOMHTMLHeadingElement class]);
146     addElementClass(HTMLNames::h5Tag, [DOMHTMLHeadingElement class]);
147     addElementClass(HTMLNames::h6Tag, [DOMHTMLHeadingElement class]);
148     addElementClass(HTMLNames::headTag, [DOMHTMLHeadElement class]);
149     addElementClass(HTMLNames::hrTag, [DOMHTMLHRElement class]);
150     addElementClass(HTMLNames::htmlTag, [DOMHTMLHtmlElement class]);
151     addElementClass(HTMLNames::iframeTag, [DOMHTMLIFrameElement class]);
152     addElementClass(HTMLNames::imgTag, [DOMHTMLImageElement class]);
153     addElementClass(HTMLNames::inputTag, [DOMHTMLInputElement class]);
154     addElementClass(HTMLNames::insTag, [DOMHTMLModElement class]);
155     addElementClass(HTMLNames::isindexTag, [DOMHTMLIsIndexElement class]);
156     addElementClass(HTMLNames::labelTag, [DOMHTMLLabelElement class]);
157     addElementClass(HTMLNames::legendTag, [DOMHTMLLegendElement class]);
158     addElementClass(HTMLNames::liTag, [DOMHTMLLIElement class]);
159     addElementClass(HTMLNames::linkTag, [DOMHTMLLinkElement class]);
160     addElementClass(HTMLNames::listingTag, [DOMHTMLPreElement class]);
161     addElementClass(HTMLNames::mapTag, [DOMHTMLMapElement class]);
162     addElementClass(HTMLNames::marqueeTag, [DOMHTMLMarqueeElement class]);
163     addElementClass(HTMLNames::menuTag, [DOMHTMLMenuElement class]);
164     addElementClass(HTMLNames::metaTag, [DOMHTMLMetaElement class]);
165     addElementClass(HTMLNames::objectTag, [DOMHTMLObjectElement class]);
166     addElementClass(HTMLNames::olTag, [DOMHTMLOListElement class]);
167     addElementClass(HTMLNames::optgroupTag, [DOMHTMLOptGroupElement class]);
168     addElementClass(HTMLNames::optionTag, [DOMHTMLOptionElement class]);
169     addElementClass(HTMLNames::pTag, [DOMHTMLParagraphElement class]);
170     addElementClass(HTMLNames::paramTag, [DOMHTMLParamElement class]);
171     addElementClass(HTMLNames::preTag, [DOMHTMLPreElement class]);
172     addElementClass(HTMLNames::qTag, [DOMHTMLQuoteElement class]);
173     addElementClass(HTMLNames::scriptTag, [DOMHTMLScriptElement class]);
174     addElementClass(HTMLNames::keygenTag, [DOMHTMLSelectElement class]);
175     addElementClass(HTMLNames::selectTag, [DOMHTMLSelectElement class]);
176     addElementClass(HTMLNames::styleTag, [DOMHTMLStyleElement class]);
177     addElementClass(HTMLNames::tableTag, [DOMHTMLTableElement class]);
178     addElementClass(HTMLNames::tbodyTag, [DOMHTMLTableSectionElement class]);
179     addElementClass(HTMLNames::tdTag, [DOMHTMLTableCellElement class]);
180     addElementClass(HTMLNames::textareaTag, [DOMHTMLTextAreaElement class]);
181     addElementClass(HTMLNames::tfootTag, [DOMHTMLTableSectionElement class]);
182     addElementClass(HTMLNames::thTag, [DOMHTMLTableCellElement class]);
183     addElementClass(HTMLNames::theadTag, [DOMHTMLTableSectionElement class]);
184     addElementClass(HTMLNames::titleTag, [DOMHTMLTitleElement class]);
185     addElementClass(HTMLNames::trTag, [DOMHTMLTableRowElement class]);
186     addElementClass(HTMLNames::ulTag, [DOMHTMLUListElement class]);
187     addElementClass(HTMLNames::xmpTag, [DOMHTMLPreElement class]);
188
189 #if ENABLE(SVG)
190     addElementClass(SVGNames::aTag, [DOMSVGAElement class]);
191 #if ENABLE(SVG_EXPERIMENTAL_FEATURES)
192     addElementClass(SVGNames::animateTag, [DOMSVGAnimateElement class]);
193     addElementClass(SVGNames::animateColorTag, [DOMSVGAnimateColorElement class]);
194     addElementClass(SVGNames::animateTransformTag, [DOMSVGAnimateTransformElement class]);
195 #endif
196     addElementClass(SVGNames::circleTag, [DOMSVGCircleElement class]);
197     addElementClass(SVGNames::clipPathTag, [DOMSVGClipPathElement class]);
198     addElementClass(SVGNames::cursorTag, [DOMSVGCursorElement class]);
199     addElementClass(SVGNames::definition_srcTag, [DOMSVGDefinitionSrcElement class]);
200     addElementClass(SVGNames::defsTag, [DOMSVGDefsElement class]);
201     addElementClass(SVGNames::descTag, [DOMSVGDescElement class]);
202     addElementClass(SVGNames::ellipseTag, [DOMSVGEllipseElement class]);
203 #if ENABLE(SVG_EXPERIMENTAL_FEATURES)
204     addElementClass(SVGNames::feBlendTag, [DOMSVGFEBlendElement class]);
205     addElementClass(SVGNames::feColorMatrixTag, [DOMSVGFEColorMatrixElement class]);
206     addElementClass(SVGNames::feComponentTransferTag, [DOMSVGFEComponentTransferElement class]);
207     addElementClass(SVGNames::feCompositeTag, [DOMSVGFECompositeElement class]);
208     addElementClass(SVGNames::feDiffuseLightingTag, [DOMSVGFEDiffuseLightingElement class]);
209     addElementClass(SVGNames::feDisplacementMapTag, [DOMSVGFEDisplacementMapElement class]);
210     addElementClass(SVGNames::feDistantLightTag, [DOMSVGFEDistantLightElement class]);
211     addElementClass(SVGNames::feFloodTag, [DOMSVGFEFloodElement class]);
212     addElementClass(SVGNames::feFuncATag, [DOMSVGFEFuncAElement class]);
213     addElementClass(SVGNames::feFuncBTag, [DOMSVGFEFuncBElement class]);
214     addElementClass(SVGNames::feFuncGTag, [DOMSVGFEFuncGElement class]);
215     addElementClass(SVGNames::feFuncRTag, [DOMSVGFEFuncRElement class]);
216     addElementClass(SVGNames::feGaussianBlurTag, [DOMSVGFEGaussianBlurElement class]);
217     addElementClass(SVGNames::feImageTag, [DOMSVGFEImageElement class]);
218     addElementClass(SVGNames::feMergeTag, [DOMSVGFEMergeElement class]);
219     addElementClass(SVGNames::feMergeNodeTag, [DOMSVGFEMergeNodeElement class]);
220     addElementClass(SVGNames::feOffsetTag, [DOMSVGFEOffsetElement class]);
221     addElementClass(SVGNames::fePointLightTag, [DOMSVGFEPointLightElement class]);
222     addElementClass(SVGNames::feSpecularLightingTag, [DOMSVGFESpecularLightingElement class]);
223     addElementClass(SVGNames::feSpotLightTag, [DOMSVGFESpotLightElement class]);
224     addElementClass(SVGNames::feTileTag, [DOMSVGFETileElement class]);
225     addElementClass(SVGNames::feTurbulenceTag, [DOMSVGFETurbulenceElement class]);
226     addElementClass(SVGNames::filterTag, [DOMSVGFilterElement class]);
227 #endif
228     addElementClass(SVGNames::font_faceTag, [DOMSVGFontFaceElement class]);
229     addElementClass(SVGNames::font_face_formatTag, [DOMSVGFontFaceFormatElement class]);
230     addElementClass(SVGNames::font_face_nameTag, [DOMSVGFontFaceNameElement class]);
231     addElementClass(SVGNames::font_face_srcTag, [DOMSVGFontFaceSrcElement class]);
232     addElementClass(SVGNames::font_face_uriTag, [DOMSVGFontFaceUriElement class]);
233     addElementClass(SVGNames::gTag, [DOMSVGGElement class]);
234     addElementClass(SVGNames::imageTag, [DOMSVGImageElement class]);
235     addElementClass(SVGNames::lineTag, [DOMSVGLineElement class]);
236     addElementClass(SVGNames::linearGradientTag, [DOMSVGLinearGradientElement class]);
237     addElementClass(SVGNames::markerTag, [DOMSVGMarkerElement class]);
238     addElementClass(SVGNames::maskTag, [DOMSVGMaskElement class]);
239     addElementClass(SVGNames::metadataTag, [DOMSVGMetadataElement class]);
240     addElementClass(SVGNames::pathTag, [DOMSVGPathElement class]);
241     addElementClass(SVGNames::patternTag, [DOMSVGPatternElement class]);
242     addElementClass(SVGNames::polygonTag, [DOMSVGPolygonElement class]);
243     addElementClass(SVGNames::polylineTag, [DOMSVGPolylineElement class]);
244     addElementClass(SVGNames::radialGradientTag, [DOMSVGRadialGradientElement class]);
245     addElementClass(SVGNames::rectTag, [DOMSVGRectElement class]);
246     addElementClass(SVGNames::scriptTag, [DOMSVGScriptElement class]);
247     addElementClass(SVGNames::setTag, [DOMSVGSetElement class]);
248     addElementClass(SVGNames::stopTag, [DOMSVGStopElement class]);
249     addElementClass(SVGNames::styleTag, [DOMSVGStyleElement class]);
250     addElementClass(SVGNames::svgTag, [DOMSVGSVGElement class]);
251     addElementClass(SVGNames::switchTag, [DOMSVGSwitchElement class]);
252     addElementClass(SVGNames::symbolTag, [DOMSVGSymbolElement class]);
253     addElementClass(SVGNames::textTag, [DOMSVGTextElement class]);
254     addElementClass(SVGNames::titleTag, [DOMSVGTitleElement class]);
255     addElementClass(SVGNames::trefTag, [DOMSVGTRefElement class]);
256     addElementClass(SVGNames::tspanTag, [DOMSVGTSpanElement class]);
257     addElementClass(SVGNames::textPathTag, [DOMSVGTextPathElement class]);
258     addElementClass(SVGNames::useTag, [DOMSVGUseElement class]);
259     addElementClass(SVGNames::viewTag, [DOMSVGViewElement class]);
260 #endif
261 }
262
263 static Class lookupElementClass(const QualifiedName& tag)
264 {
265     // Do a special lookup to ignore element prefixes
266     if (tag.hasPrefix())
267         return elementClassMap->get(QualifiedName(nullAtom, tag.localName(), tag.namespaceURI()).impl());
268     
269     return elementClassMap->get(tag.impl());
270 }
271
272 static Class elementClass(const QualifiedName& tag, Class defaultClass)
273 {
274     if (!elementClassMap)
275         createElementClassMap();
276     Class objcClass = lookupElementClass(tag);
277     if (!objcClass)
278         objcClass = defaultClass;
279     return objcClass;
280 }
281
282 static NSArray *kit(const Vector<IntRect>& rects)
283 {
284     size_t size = rects.size();
285     NSMutableArray *array = [NSMutableArray arrayWithCapacity:size];
286     for (size_t i = 0; i < size; ++i)
287         [array addObject:[NSValue valueWithRect:rects[i]]];
288     return array;
289 }
290
291 } // namespace WebCore
292
293 @implementation DOMNode (WebCoreInternal)
294
295 // FIXME: should this go in the main implementation?
296 - (NSString *)description
297 {
298     if (!_internal)
299         return [NSString stringWithFormat:@"<%@: null>", [[self class] description], self];
300
301     NSString *value = [self nodeValue];
302     if (value)
303         return [NSString stringWithFormat:@"<%@ [%@]: %p '%@'>",
304             [[self class] description], [self nodeName], _internal, value];
305
306     return [NSString stringWithFormat:@"<%@ [%@]: %p>", [[self class] description], [self nodeName], _internal];
307 }
308
309 - (id)_initWithNode:(WebCore::Node *)impl
310 {
311     ASSERT(impl);
312
313     [super _init];
314     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
315     impl->ref();
316     WebCore::addDOMWrapper(self, impl);
317     return self;
318 }
319
320 + (DOMNode *)_wrapNode:(WebCore::Node *)impl
321 {
322     if (!impl)
323         return nil;
324
325     id cachedInstance;
326     cachedInstance = WebCore::getDOMWrapper(impl);
327     if (cachedInstance)
328         return [[cachedInstance retain] autorelease];
329
330     Class wrapperClass = nil;
331     switch (impl->nodeType()) {
332         case WebCore::Node::ELEMENT_NODE:
333             if (impl->isHTMLElement())
334                 wrapperClass = WebCore::elementClass(static_cast<WebCore::HTMLElement*>(impl)->tagQName(), [DOMHTMLElement class]);
335 #if ENABLE(SVG)
336             else if (impl->isSVGElement())
337                 wrapperClass = WebCore::elementClass(static_cast<WebCore::SVGElement*>(impl)->tagQName(), [DOMSVGElement class]);
338 #endif
339             else
340                 wrapperClass = [DOMElement class];
341             break;
342         case WebCore::Node::ATTRIBUTE_NODE:
343             wrapperClass = [DOMAttr class];
344             break;
345         case WebCore::Node::TEXT_NODE:
346             wrapperClass = [DOMText class];
347             break;
348         case WebCore::Node::CDATA_SECTION_NODE:
349             wrapperClass = [DOMCDATASection class];
350             break;
351         case WebCore::Node::ENTITY_REFERENCE_NODE:
352             wrapperClass = [DOMEntityReference class];
353             break;
354         case WebCore::Node::ENTITY_NODE:
355             wrapperClass = [DOMEntity class];
356             break;
357         case WebCore::Node::PROCESSING_INSTRUCTION_NODE:
358             wrapperClass = [DOMProcessingInstruction class];
359             break;
360         case WebCore::Node::COMMENT_NODE:
361             wrapperClass = [DOMComment class];
362             break;
363         case WebCore::Node::DOCUMENT_NODE:
364             if (static_cast<WebCore::Document*>(impl)->isHTMLDocument())
365                 wrapperClass = [DOMHTMLDocument class];
366 #if ENABLE(SVG)
367             else if (static_cast<WebCore::Document*>(impl)->isSVGDocument())
368                 wrapperClass = [DOMSVGDocument class];
369 #endif
370             else
371                 wrapperClass = [DOMDocument class];
372             break;
373         case WebCore::Node::DOCUMENT_TYPE_NODE:
374             wrapperClass = [DOMDocumentType class];
375             break;
376         case WebCore::Node::DOCUMENT_FRAGMENT_NODE:
377             wrapperClass = [DOMDocumentFragment class];
378             break;
379         case WebCore::Node::NOTATION_NODE:
380             wrapperClass = [DOMNotation class];
381             break;
382         case WebCore::Node::XPATH_NAMESPACE_NODE:
383             // FIXME: Create an XPath objective C wrapper
384             // See http://bugs.webkit.org/show_bug.cgi?id=8755
385             return nil;
386     }
387     return [[[wrapperClass alloc] _initWithNode:impl] autorelease];
388 }
389
390 + (id <DOMEventTarget>)_wrapEventTarget:(WebCore::EventTarget *)eventTarget
391 {
392     if (!eventTarget)
393         return nil;
394     
395     // We don't have an ObjC binding for XMLHttpRequest
396     return [DOMNode _wrapNode:eventTarget->toNode()];
397 }
398
399 - (WebCore::Node *)_node
400 {
401     return reinterpret_cast<WebCore::Node*>(_internal);
402 }
403
404 - (KJS::Bindings::RootObject*)_rootObject
405 {
406     if (WebCore::Node *n = [self _node]) {
407         if (WebCore::Frame* frame = n->document()->frame())
408             return frame->bindingRootObject();
409     }
410     return 0;
411 }
412
413 @end
414
415 @implementation DOMNode (DOMNodeExtensions)
416
417 // FIXME: This should be implemented in Node so we don't have to fetch the renderer.
418 // If it was, we could even autogenerate.
419 - (NSRect)boundingBox
420 {
421     [self _node]->document()->updateLayoutIgnorePendingStylesheets();
422     WebCore::RenderObject *renderer = [self _node]->renderer();
423     if (renderer)
424         return renderer->absoluteBoundingBoxRect();
425     return NSZeroRect;
426 }
427
428 // FIXME: This should be implemented in Node so we don't have to fetch the renderer.
429 // If it was, we could even autogenerate.
430 - (NSArray *)lineBoxRects
431 {
432     [self _node]->document()->updateLayoutIgnorePendingStylesheets();
433     WebCore::RenderObject *renderer = [self _node]->renderer();
434     if (renderer) {
435         Vector<WebCore::IntRect> rects;
436         renderer->addLineBoxRects(rects);
437         return kit(rects);
438     }
439     return nil;
440 }
441
442 @end
443
444 @implementation DOMRange (DOMRangeExtensions)
445
446 - (NSRect)boundingBox
447 {
448     [self _range]->ownerDocument()->updateLayoutIgnorePendingStylesheets();
449     return [self _range]->boundingBox();
450 }
451
452 - (NSArray *)lineBoxRects
453 {
454     Vector<WebCore::IntRect> rects;
455     [self _range]->ownerDocument()->updateLayoutIgnorePendingStylesheets();
456     [self _range]->addLineBoxRects(rects);
457     return kit(rects);
458 }
459
460 @end
461
462 // FIXME: this should be auto-generated
463 @implementation DOMNode (DOMEventTarget)
464
465 - (void)addEventListener:(NSString *)type listener:(id <DOMEventListener>)listener useCapture:(BOOL)useCapture
466 {
467     if (![self _node]->isEventTargetNode())
468         WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR);
469     
470     WebCore::EventListener *wrapper = WebCore::ObjCEventListener::create(listener);
471     WebCore::EventTargetNodeCast([self _node])->addEventListener(type, wrapper, useCapture);
472     wrapper->deref();
473 }
474
475 - (void)addEventListener:(NSString *)type :(id <DOMEventListener>)listener :(BOOL)useCapture
476 {
477     // FIXME: this method can be removed once Mail changes to use the new method <rdar://problem/4746649>
478     [self addEventListener:type listener:listener useCapture:useCapture];
479 }
480
481 - (void)removeEventListener:(NSString *)type listener:(id <DOMEventListener>)listener useCapture:(BOOL)useCapture
482 {
483     if (![self _node]->isEventTargetNode())
484         WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR);
485
486     if (WebCore::EventListener *wrapper = WebCore::ObjCEventListener::find(listener))
487         WebCore::EventTargetNodeCast([self _node])->removeEventListener(type, wrapper, useCapture);
488 }
489
490 - (void)removeEventListener:(NSString *)type :(id <DOMEventListener>)listener :(BOOL)useCapture
491 {
492     // FIXME: this method can be removed once Mail changes to use the new method <rdar://problem/4746649>
493     [self removeEventListener:type listener:listener useCapture:useCapture];
494 }
495
496 - (BOOL)dispatchEvent:(DOMEvent *)event
497 {
498     if (![self _node]->isEventTargetNode())
499         WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR);
500
501     WebCore::ExceptionCode ec = 0;
502     BOOL result = WebCore::EventTargetNodeCast([self _node])->dispatchEvent([event _event], ec);
503     WebCore::raiseOnDOMError(ec);
504     return result;
505 }
506
507 @end
508
509 //------------------------------------------------------------------------------------------
510 // DOMElement
511
512 // FIXME: this should be auto-generated in DOMElement.mm
513 @implementation DOMElement (DOMElementAppKitExtensions)
514
515 // FIXME: this should be implemented in the implementation
516 - (NSImage*)image
517 {
518     WebCore::RenderObject* renderer = [self _element]->renderer();
519     if (renderer && renderer->isImage()) {
520         WebCore::RenderImage* img = static_cast<WebCore::RenderImage*>(renderer);
521         if (img->cachedImage() && !img->cachedImage()->errorOccurred())
522             return img->cachedImage()->image()->getNSImage();
523     }
524     return nil;
525 }
526
527 @end
528
529 @implementation DOMElement (WebPrivate)
530
531 // FIXME: this should be implemented in the implementation
532 - (NSFont *)_font
533 {
534     WebCore::RenderObject* renderer = [self _element]->renderer();
535     if (renderer)
536         return renderer->style()->font().primaryFont()->getNSFont();
537     return nil;
538 }
539
540 // FIXME: this should be implemented in the implementation
541 - (NSData *)_imageTIFFRepresentation
542 {
543     WebCore::RenderObject* renderer = [self _element]->renderer();
544     if (renderer && renderer->isImage()) {
545         WebCore::RenderImage* img = static_cast<WebCore::RenderImage*>(renderer);
546         if (img->cachedImage() && !img->cachedImage()->errorOccurred())
547             return (NSData*)(img->cachedImage()->image()->getTIFFRepresentation());
548     }
549     return nil;
550 }
551
552 - (NSRect)_windowClipRect
553 {
554     WebCore::RenderObject* renderer = [self _element]->renderer();
555     if (renderer && renderer->view()) {
556         WebCore::FrameView* frameView = renderer->view()->frameView();
557         if (!frameView)
558             return WebCore::IntRect();
559         return frameView->windowClipRectForLayer(renderer->enclosingLayer(), true);
560     }
561     return WebCore::IntRect();
562 }
563
564 // FIXME: this should be implemented in the implementation
565 - (NSURL *)_getURLAttribute:(NSString *)name
566 {
567     ASSERT(name);
568     WebCore::Element* element = [self _element];
569     ASSERT(element);
570     return WebCore::KURL(element->document()->completeURL(parseURL(element->getAttribute(name)).deprecatedString())).getNSURL();
571 }
572
573 // FIXME: this should be implemented in the implementation
574 - (void *)_NPObject
575 {
576 #if USE(NPOBJECT)
577     WebCore::Element* element = [self _element];
578     if (element->hasTagName(WebCore::HTMLNames::appletTag) || element->hasTagName(WebCore::HTMLNames::embedTag) || element->hasTagName(WebCore::HTMLNames::objectTag))
579         return static_cast<WebCore::HTMLPlugInElement*>(element)->getNPObject();
580 #endif
581     return 0;
582 }
583
584 // FIXME: this should be implemented in the implementation
585 - (BOOL)isFocused
586 {
587     WebCore::Element* impl = [self _element];
588     if (impl->document()->focusedNode() == impl)
589         return YES;
590     return NO;
591 }
592
593 @end
594
595
596 //------------------------------------------------------------------------------------------
597 // DOMRange
598
599 @implementation DOMRange (WebPrivate)
600
601 - (NSString *)description
602 {
603     if (!_internal)
604         return @"<DOMRange: null>";
605     return [NSString stringWithFormat:@"<DOMRange: %@ %d %@ %d>",
606                [self startContainer], [self startOffset], [self endContainer], [self endOffset]];
607 }
608
609 // FIXME: this should be removed as soon as all internal Apple uses of it have been replaced with
610 // calls to the public method - (NSString *)text.
611 - (NSString *)_text
612 {
613     return [self text];
614 }
615
616 @end
617
618
619 //------------------------------------------------------------------------------------------
620 // DOMNodeFilter
621
622 // FIXME: This implementation should be in it's own file.
623
624 @implementation DOMNodeFilter
625
626 - (id)_initWithNodeFilter:(WebCore::NodeFilter *)impl
627 {
628     ASSERT(impl);
629
630     [super _init];
631     _internal = reinterpret_cast<DOMObjectInternal*>(impl);
632     impl->ref();
633     WebCore::addDOMWrapper(self, impl);
634     return self;
635 }
636
637 + (DOMNodeFilter *)_wrapNodeFilter:(WebCore::NodeFilter *)impl
638 {
639     if (!impl)
640         return nil;
641     
642     id cachedInstance;
643     cachedInstance = WebCore::getDOMWrapper(impl);
644     if (cachedInstance)
645         return [[cachedInstance retain] autorelease];
646     
647     return [[[self alloc] _initWithNodeFilter:impl] autorelease];
648 }
649
650 - (WebCore::NodeFilter *)_nodeFilter
651 {
652     return reinterpret_cast<WebCore::NodeFilter*>(_internal);
653 }
654
655 - (void)dealloc
656 {
657     if (_internal)
658         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
659     [super dealloc];
660 }
661
662 - (void)finalize
663 {
664     if (_internal)
665         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
666     [super finalize];
667 }
668
669 - (short)acceptNode:(DOMNode *)node
670 {
671     return [self _nodeFilter]->acceptNode([node _node]);
672 }
673
674 @end
675
676
677 //------------------------------------------------------------------------------------------
678 // ObjCNodeFilterCondition
679
680 class ObjCNodeFilterCondition : public WebCore::NodeFilterCondition {
681 public:
682     ObjCNodeFilterCondition(id <DOMNodeFilter>);
683     virtual ~ObjCNodeFilterCondition();
684     virtual short acceptNode(WebCore::Node*) const;
685
686 private:
687     ObjCNodeFilterCondition(const ObjCNodeFilterCondition&);
688     ObjCNodeFilterCondition &operator=(const ObjCNodeFilterCondition&);
689
690     id <DOMNodeFilter> m_filter;
691 };
692
693 ObjCNodeFilterCondition::ObjCNodeFilterCondition(id <DOMNodeFilter> filter)
694     : m_filter(filter)
695 {
696     ASSERT(m_filter);
697     HardRetain(m_filter);
698 }
699
700 ObjCNodeFilterCondition::~ObjCNodeFilterCondition()
701 {
702     HardRelease(m_filter);
703 }
704
705 short ObjCNodeFilterCondition::acceptNode(WebCore::Node* node) const
706 {
707     if (!node)
708         return WebCore::NodeFilter::FILTER_REJECT;
709     return [m_filter acceptNode:[DOMNode _wrapNode:node]];
710 }
711
712
713 //------------------------------------------------------------------------------------------
714 // DOMDocument (DOMDocumentTraversal)
715
716 // FIXME: this should be auto-generated in DOMDocument.mm
717 @implementation DOMDocument (DOMDocumentTraversal)
718
719 - (DOMNodeIterator *)createNodeIterator:(DOMNode *)root whatToShow:(unsigned)whatToShow filter:(id <DOMNodeFilter>)filter expandEntityReferences:(BOOL)expandEntityReferences
720 {
721     WebCore::NodeFilter* cppFilter = 0;
722     if (filter)
723         cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter));
724     WebCore::ExceptionCode ec = 0;
725     RefPtr<WebCore::NodeIterator> impl = [self _document]->createNodeIterator([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
726     WebCore::raiseOnDOMError(ec);
727     return [DOMNodeIterator _wrapNodeIterator:impl.get() filter:filter];
728 }
729
730 - (DOMTreeWalker *)createTreeWalker:(DOMNode *)root whatToShow:(unsigned)whatToShow filter:(id <DOMNodeFilter>)filter expandEntityReferences:(BOOL)expandEntityReferences
731 {
732     WebCore::NodeFilter* cppFilter = 0;
733     if (filter)
734         cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter));
735     WebCore::ExceptionCode ec = 0;
736     RefPtr<WebCore::TreeWalker> impl = [self _document]->createTreeWalker([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
737     WebCore::raiseOnDOMError(ec);
738     return [DOMTreeWalker _wrapTreeWalker:impl.get() filter:filter];
739 }
740
741 @end
742
743 @implementation DOMDocument (DOMDocumentTraversalDeprecated)
744
745 - (DOMNodeIterator *)createNodeIterator:(DOMNode *)root :(unsigned)whatToShow :(id <DOMNodeFilter>)filter :(BOOL)expandEntityReferences
746 {
747     return [self createNodeIterator:root whatToShow:whatToShow filter:filter expandEntityReferences:expandEntityReferences];
748 }
749
750 - (DOMTreeWalker *)createTreeWalker:(DOMNode *)root :(unsigned)whatToShow :(id <DOMNodeFilter>)filter :(BOOL)expandEntityReferences
751 {
752     return [self createTreeWalker:root whatToShow:whatToShow filter:filter expandEntityReferences:expandEntityReferences];
753 }
754
755 @end
756
757
758 //------------------------------------------------------------------------------------------
759 // ObjCEventListener
760
761 namespace WebCore {
762
763 ObjCEventListener* ObjCEventListener::find(id <DOMEventListener> listener)
764 {
765     if (ListenerMap* map = listenerMap)
766         return map->get(listener);
767     return 0;
768 }
769
770 ObjCEventListener *ObjCEventListener::create(id <DOMEventListener> listener)
771 {
772     ObjCEventListener* wrapper = find(listener);
773     if (!wrapper)
774         wrapper = new ObjCEventListener(listener);
775     wrapper->ref();
776     return wrapper;
777 }
778
779 ObjCEventListener::ObjCEventListener(id <DOMEventListener> listener)
780     : m_listener([listener retain])
781 {
782     ListenerMap* map = listenerMap;
783     if (!map) {
784         map = new ListenerMap;
785         listenerMap = map;
786     }
787     map->set(listener, this);
788 }
789
790 ObjCEventListener::~ObjCEventListener()
791 {
792     listenerMap->remove(m_listener);
793     [m_listener release];
794 }
795
796 void ObjCEventListener::handleEvent(Event* event, bool)
797 {
798     [m_listener handleEvent:[DOMEvent _wrapEvent:event]];
799 }
800
801 } // namespace WebCore