/* * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2006 James G. Speth (speth@end.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "DOM.h" #import "CDATASection.h" #import "CSSHelper.h" #import "CSSStyleSheet.h" #import "Comment.h" #import "DOMHTMLCanvasElement.h" #import "DOMInternal.h" #import "DOMPrivate.h" #import "Document.h" #import "DocumentFragment.h" #import "DocumentType.h" #import "EntityReference.h" #import "Event.h" #import "EventListener.h" #import "EventTarget.h" #import "ExceptionHandlers.h" #import "FontData.h" #import "FoundationExtras.h" #import "Frame.h" #import "FrameView.h" #import "HTMLDocument.h" #import "HTMLNames.h" #import "HTMLPlugInElement.h" #import "Image.h" #import "IntRect.h" #import "NodeFilter.h" #import "NodeFilterCondition.h" #import "NodeIterator.h" #import "NodeList.h" #import "ProcessingInstruction.h" #import "QualifiedName.h" #import "Range.h" #import "RenderImage.h" #import "RenderView.h" #import "Text.h" #import "TreeWalker.h" #import "WebScriptObjectPrivate.h" #import #import #if ENABLE(SVG) #import "SVGDocument.h" #import "SVGElement.h" #import "SVGNames.h" #endif namespace WebCore { class ObjCEventListener : public EventListener { public: static ObjCEventListener* find(id ); static ObjCEventListener* create(id ); private: ObjCEventListener(id ); virtual ~ObjCEventListener(); virtual void handleEvent(Event*, bool isWindowEvent); id m_listener; }; typedef HashMap ListenerMap; static ListenerMap* listenerMap; } // namespace WebCore //------------------------------------------------------------------------------------------ // DOMNode namespace WebCore { typedef HashMap ObjCClassMap; static ObjCClassMap* elementClassMap; static void addElementClass(const QualifiedName& tag, Class objCClass) { elementClassMap->set(tag.impl(), objCClass); } static void createElementClassMap() { // Create the table. elementClassMap = new ObjCClassMap; // FIXME: Reflect marquee once the API has been determined. // Populate it with HTML and SVG element classes. addElementClass(HTMLNames::aTag, [DOMHTMLAnchorElement class]); addElementClass(HTMLNames::appletTag, [DOMHTMLAppletElement class]); addElementClass(HTMLNames::areaTag, [DOMHTMLAreaElement class]); addElementClass(HTMLNames::baseTag, [DOMHTMLBaseElement class]); addElementClass(HTMLNames::basefontTag, [DOMHTMLBaseFontElement class]); addElementClass(HTMLNames::bodyTag, [DOMHTMLBodyElement class]); addElementClass(HTMLNames::brTag, [DOMHTMLBRElement class]); addElementClass(HTMLNames::buttonTag, [DOMHTMLButtonElement class]); addElementClass(HTMLNames::canvasTag, [DOMHTMLCanvasElement class]); addElementClass(HTMLNames::captionTag, [DOMHTMLTableCaptionElement class]); addElementClass(HTMLNames::colTag, [DOMHTMLTableColElement class]); addElementClass(HTMLNames::colgroupTag, [DOMHTMLTableColElement class]); addElementClass(HTMLNames::delTag, [DOMHTMLModElement class]); addElementClass(HTMLNames::dirTag, [DOMHTMLDirectoryElement class]); addElementClass(HTMLNames::divTag, [DOMHTMLDivElement class]); addElementClass(HTMLNames::dlTag, [DOMHTMLDListElement class]); addElementClass(HTMLNames::embedTag, [DOMHTMLEmbedElement class]); addElementClass(HTMLNames::fieldsetTag, [DOMHTMLFieldSetElement class]); addElementClass(HTMLNames::fontTag, [DOMHTMLFontElement class]); addElementClass(HTMLNames::formTag, [DOMHTMLFormElement class]); addElementClass(HTMLNames::frameTag, [DOMHTMLFrameElement class]); addElementClass(HTMLNames::framesetTag, [DOMHTMLFrameSetElement class]); addElementClass(HTMLNames::h1Tag, [DOMHTMLHeadingElement class]); addElementClass(HTMLNames::h2Tag, [DOMHTMLHeadingElement class]); addElementClass(HTMLNames::h3Tag, [DOMHTMLHeadingElement class]); addElementClass(HTMLNames::h4Tag, [DOMHTMLHeadingElement class]); addElementClass(HTMLNames::h5Tag, [DOMHTMLHeadingElement class]); addElementClass(HTMLNames::h6Tag, [DOMHTMLHeadingElement class]); addElementClass(HTMLNames::headTag, [DOMHTMLHeadElement class]); addElementClass(HTMLNames::hrTag, [DOMHTMLHRElement class]); addElementClass(HTMLNames::htmlTag, [DOMHTMLHtmlElement class]); addElementClass(HTMLNames::iframeTag, [DOMHTMLIFrameElement class]); addElementClass(HTMLNames::imgTag, [DOMHTMLImageElement class]); addElementClass(HTMLNames::inputTag, [DOMHTMLInputElement class]); addElementClass(HTMLNames::insTag, [DOMHTMLModElement class]); addElementClass(HTMLNames::isindexTag, [DOMHTMLIsIndexElement class]); addElementClass(HTMLNames::labelTag, [DOMHTMLLabelElement class]); addElementClass(HTMLNames::legendTag, [DOMHTMLLegendElement class]); addElementClass(HTMLNames::liTag, [DOMHTMLLIElement class]); addElementClass(HTMLNames::linkTag, [DOMHTMLLinkElement class]); addElementClass(HTMLNames::listingTag, [DOMHTMLPreElement class]); addElementClass(HTMLNames::mapTag, [DOMHTMLMapElement class]); addElementClass(HTMLNames::marqueeTag, [DOMHTMLMarqueeElement class]); addElementClass(HTMLNames::menuTag, [DOMHTMLMenuElement class]); addElementClass(HTMLNames::metaTag, [DOMHTMLMetaElement class]); addElementClass(HTMLNames::objectTag, [DOMHTMLObjectElement class]); addElementClass(HTMLNames::olTag, [DOMHTMLOListElement class]); addElementClass(HTMLNames::optgroupTag, [DOMHTMLOptGroupElement class]); addElementClass(HTMLNames::optionTag, [DOMHTMLOptionElement class]); addElementClass(HTMLNames::pTag, [DOMHTMLParagraphElement class]); addElementClass(HTMLNames::paramTag, [DOMHTMLParamElement class]); addElementClass(HTMLNames::preTag, [DOMHTMLPreElement class]); addElementClass(HTMLNames::qTag, [DOMHTMLQuoteElement class]); addElementClass(HTMLNames::scriptTag, [DOMHTMLScriptElement class]); addElementClass(HTMLNames::keygenTag, [DOMHTMLSelectElement class]); addElementClass(HTMLNames::selectTag, [DOMHTMLSelectElement class]); addElementClass(HTMLNames::styleTag, [DOMHTMLStyleElement class]); addElementClass(HTMLNames::tableTag, [DOMHTMLTableElement class]); addElementClass(HTMLNames::tbodyTag, [DOMHTMLTableSectionElement class]); addElementClass(HTMLNames::tdTag, [DOMHTMLTableCellElement class]); addElementClass(HTMLNames::textareaTag, [DOMHTMLTextAreaElement class]); addElementClass(HTMLNames::tfootTag, [DOMHTMLTableSectionElement class]); addElementClass(HTMLNames::thTag, [DOMHTMLTableCellElement class]); addElementClass(HTMLNames::theadTag, [DOMHTMLTableSectionElement class]); addElementClass(HTMLNames::titleTag, [DOMHTMLTitleElement class]); addElementClass(HTMLNames::trTag, [DOMHTMLTableRowElement class]); addElementClass(HTMLNames::ulTag, [DOMHTMLUListElement class]); addElementClass(HTMLNames::xmpTag, [DOMHTMLPreElement class]); #if ENABLE(SVG) addElementClass(SVGNames::aTag, [DOMSVGAElement class]); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) addElementClass(SVGNames::animateTag, [DOMSVGAnimateElement class]); addElementClass(SVGNames::animateColorTag, [DOMSVGAnimateColorElement class]); addElementClass(SVGNames::animateTransformTag, [DOMSVGAnimateTransformElement class]); #endif addElementClass(SVGNames::circleTag, [DOMSVGCircleElement class]); addElementClass(SVGNames::clipPathTag, [DOMSVGClipPathElement class]); addElementClass(SVGNames::cursorTag, [DOMSVGCursorElement class]); addElementClass(SVGNames::defsTag, [DOMSVGDefsElement class]); addElementClass(SVGNames::descTag, [DOMSVGDescElement class]); addElementClass(SVGNames::ellipseTag, [DOMSVGEllipseElement class]); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) addElementClass(SVGNames::feBlendTag, [DOMSVGFEBlendElement class]); addElementClass(SVGNames::feColorMatrixTag, [DOMSVGFEColorMatrixElement class]); addElementClass(SVGNames::feComponentTransferTag, [DOMSVGFEComponentTransferElement class]); addElementClass(SVGNames::feCompositeTag, [DOMSVGFECompositeElement class]); addElementClass(SVGNames::feDiffuseLightingTag, [DOMSVGFEDiffuseLightingElement class]); addElementClass(SVGNames::feDisplacementMapTag, [DOMSVGFEDisplacementMapElement class]); addElementClass(SVGNames::feDistantLightTag, [DOMSVGFEDistantLightElement class]); addElementClass(SVGNames::feFloodTag, [DOMSVGFEFloodElement class]); addElementClass(SVGNames::feFuncATag, [DOMSVGFEFuncAElement class]); addElementClass(SVGNames::feFuncBTag, [DOMSVGFEFuncBElement class]); addElementClass(SVGNames::feFuncGTag, [DOMSVGFEFuncGElement class]); addElementClass(SVGNames::feFuncRTag, [DOMSVGFEFuncRElement class]); addElementClass(SVGNames::feGaussianBlurTag, [DOMSVGFEGaussianBlurElement class]); addElementClass(SVGNames::feImageTag, [DOMSVGFEImageElement class]); addElementClass(SVGNames::feMergeTag, [DOMSVGFEMergeElement class]); addElementClass(SVGNames::feMergeNodeTag, [DOMSVGFEMergeNodeElement class]); addElementClass(SVGNames::feOffsetTag, [DOMSVGFEOffsetElement class]); addElementClass(SVGNames::fePointLightTag, [DOMSVGFEPointLightElement class]); addElementClass(SVGNames::feSpecularLightingTag, [DOMSVGFESpecularLightingElement class]); addElementClass(SVGNames::feSpotLightTag, [DOMSVGFESpotLightElement class]); addElementClass(SVGNames::feTileTag, [DOMSVGFETileElement class]); addElementClass(SVGNames::feTurbulenceTag, [DOMSVGFETurbulenceElement class]); addElementClass(SVGNames::filterTag, [DOMSVGFilterElement class]); addElementClass(SVGNames::foreignObjectTag, [DOMSVGForeignObjectElement class]); #endif addElementClass(SVGNames::gTag, [DOMSVGGElement class]); addElementClass(SVGNames::imageTag, [DOMSVGImageElement class]); addElementClass(SVGNames::lineTag, [DOMSVGLineElement class]); addElementClass(SVGNames::linearGradientTag, [DOMSVGLinearGradientElement class]); addElementClass(SVGNames::markerTag, [DOMSVGMarkerElement class]); addElementClass(SVGNames::maskTag, [DOMSVGMaskElement class]); addElementClass(SVGNames::metadataTag, [DOMSVGMetadataElement class]); addElementClass(SVGNames::pathTag, [DOMSVGPathElement class]); addElementClass(SVGNames::patternTag, [DOMSVGPatternElement class]); addElementClass(SVGNames::polygonTag, [DOMSVGPolygonElement class]); addElementClass(SVGNames::polylineTag, [DOMSVGPolylineElement class]); addElementClass(SVGNames::radialGradientTag, [DOMSVGRadialGradientElement class]); addElementClass(SVGNames::rectTag, [DOMSVGRectElement class]); addElementClass(SVGNames::scriptTag, [DOMSVGScriptElement class]); addElementClass(SVGNames::setTag, [DOMSVGSetElement class]); addElementClass(SVGNames::stopTag, [DOMSVGStopElement class]); addElementClass(SVGNames::styleTag, [DOMSVGStyleElement class]); addElementClass(SVGNames::svgTag, [DOMSVGSVGElement class]); addElementClass(SVGNames::switchTag, [DOMSVGSwitchElement class]); addElementClass(SVGNames::symbolTag, [DOMSVGSymbolElement class]); addElementClass(SVGNames::textTag, [DOMSVGTextElement class]); addElementClass(SVGNames::titleTag, [DOMSVGTitleElement class]); addElementClass(SVGNames::trefTag, [DOMSVGTRefElement class]); addElementClass(SVGNames::tspanTag, [DOMSVGTSpanElement class]); addElementClass(SVGNames::useTag, [DOMSVGUseElement class]); addElementClass(SVGNames::viewTag, [DOMSVGViewElement class]); #endif } static Class elementClass(const QualifiedName& tag, Class defaultClass) { if (!elementClassMap) createElementClassMap(); Class objcClass = elementClassMap->get(tag.impl()); if (!objcClass) objcClass = defaultClass; return objcClass; } static NSArray *kit(const Vector& rects) { size_t size = rects.size(); NSMutableArray *array = [NSMutableArray arrayWithCapacity:size]; for (size_t i = 0; i < size; ++i) [array addObject:[NSValue valueWithRect:rects[i]]]; return array; } } // namespace WebCore @implementation DOMNode (WebCoreInternal) // FIXME: should this go in the main implementation? - (NSString *)description { if (!_internal) return [NSString stringWithFormat:@"<%@: null>", [[self class] description], self]; NSString *value = [self nodeValue]; if (value) return [NSString stringWithFormat:@"<%@ [%@]: %p '%@'>", [[self class] description], [self nodeName], _internal, value]; return [NSString stringWithFormat:@"<%@ [%@]: %p>", [[self class] description], [self nodeName], _internal]; } - (id)_initWithNode:(WebCore::Node *)impl { ASSERT(impl); [super _init]; _internal = reinterpret_cast(impl); impl->ref(); WebCore::addDOMWrapper(self, impl); return self; } + (DOMNode *)_wrapNode:(WebCore::Node *)impl { if (!impl) return nil; id cachedInstance; cachedInstance = WebCore::getDOMWrapper(impl); if (cachedInstance) return [[cachedInstance retain] autorelease]; Class wrapperClass = nil; switch (impl->nodeType()) { case WebCore::Node::ELEMENT_NODE: if (impl->isHTMLElement()) wrapperClass = WebCore::elementClass(static_cast(impl)->tagQName(), [DOMHTMLElement class]); #if ENABLE(SVG) else if (impl->isSVGElement()) wrapperClass = WebCore::elementClass(static_cast(impl)->tagQName(), [DOMSVGElement class]); #endif else wrapperClass = [DOMElement class]; break; case WebCore::Node::ATTRIBUTE_NODE: wrapperClass = [DOMAttr class]; break; case WebCore::Node::TEXT_NODE: wrapperClass = [DOMText class]; break; case WebCore::Node::CDATA_SECTION_NODE: wrapperClass = [DOMCDATASection class]; break; case WebCore::Node::ENTITY_REFERENCE_NODE: wrapperClass = [DOMEntityReference class]; break; case WebCore::Node::ENTITY_NODE: wrapperClass = [DOMEntity class]; break; case WebCore::Node::PROCESSING_INSTRUCTION_NODE: wrapperClass = [DOMProcessingInstruction class]; break; case WebCore::Node::COMMENT_NODE: wrapperClass = [DOMComment class]; break; case WebCore::Node::DOCUMENT_NODE: if (static_cast(impl)->isHTMLDocument()) wrapperClass = [DOMHTMLDocument class]; #if ENABLE(SVG) else if (static_cast(impl)->isSVGDocument()) wrapperClass = [DOMSVGDocument class]; #endif else wrapperClass = [DOMDocument class]; break; case WebCore::Node::DOCUMENT_TYPE_NODE: wrapperClass = [DOMDocumentType class]; break; case WebCore::Node::DOCUMENT_FRAGMENT_NODE: wrapperClass = [DOMDocumentFragment class]; break; case WebCore::Node::NOTATION_NODE: wrapperClass = [DOMNotation class]; break; case WebCore::Node::XPATH_NAMESPACE_NODE: // FIXME: Create an XPath objective C wrapper // See http://bugs.webkit.org/show_bug.cgi?id=8755 return nil; } return [[[wrapperClass alloc] _initWithNode:impl] autorelease]; } + (id )_wrapEventTarget:(WebCore::EventTarget *)eventTarget { if (!eventTarget) return nil; // We don't have an ObjC binding for XMLHttpRequest return [DOMNode _wrapNode:eventTarget->toNode()]; } - (WebCore::Node *)_node { return reinterpret_cast(_internal); } - (KJS::Bindings::RootObject*)_rootObject { if (WebCore::Node *n = [self _node]) { if (WebCore::Frame* frame = n->document()->frame()) return frame->bindingRootObject(); } return 0; } @end @implementation DOMNode (DOMNodeExtensions) // FIXME: This should be implemented in Node so we don't have to fetch the renderer. // If it was, we could even autogenerate. - (NSRect)boundingBox { [self _node]->document()->updateLayoutIgnorePendingStylesheets(); WebCore::RenderObject *renderer = [self _node]->renderer(); if (renderer) return renderer->absoluteBoundingBoxRect(); return NSZeroRect; } // FIXME: This should be implemented in Node so we don't have to fetch the renderer. // If it was, we could even autogenerate. - (NSArray *)lineBoxRects { [self _node]->document()->updateLayoutIgnorePendingStylesheets(); WebCore::RenderObject *renderer = [self _node]->renderer(); if (renderer) { Vector rects; renderer->addLineBoxRects(rects); return kit(rects); } return nil; } @end @implementation DOMRange (DOMRangeExtensions) - (NSRect)boundingBox { [self _range]->ownerDocument()->updateLayoutIgnorePendingStylesheets(); return [self _range]->boundingBox(); } - (NSArray *)lineBoxRects { Vector rects; [self _range]->ownerDocument()->updateLayoutIgnorePendingStylesheets(); [self _range]->addLineBoxRects(rects); return kit(rects); } @end // FIXME: this should be auto-generated @implementation DOMNode (DOMEventTarget) - (void)addEventListener:(NSString *)type listener:(id )listener useCapture:(BOOL)useCapture { if (![self _node]->isEventTargetNode()) WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR); WebCore::EventListener *wrapper = WebCore::ObjCEventListener::create(listener); WebCore::EventTargetNodeCast([self _node])->addEventListener(type, wrapper, useCapture); wrapper->deref(); } - (void)addEventListener:(NSString *)type :(id )listener :(BOOL)useCapture { // FIXME: this method can be removed once Mail changes to use the new method [self addEventListener:type listener:listener useCapture:useCapture]; } - (void)removeEventListener:(NSString *)type listener:(id )listener useCapture:(BOOL)useCapture { if (![self _node]->isEventTargetNode()) WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR); if (WebCore::EventListener *wrapper = WebCore::ObjCEventListener::find(listener)) WebCore::EventTargetNodeCast([self _node])->removeEventListener(type, wrapper, useCapture); } - (void)removeEventListener:(NSString *)type :(id )listener :(BOOL)useCapture { // FIXME: this method can be removed once Mail changes to use the new method [self removeEventListener:type listener:listener useCapture:useCapture]; } - (BOOL)dispatchEvent:(DOMEvent *)event { if (![self _node]->isEventTargetNode()) WebCore::raiseDOMException(DOM_NOT_SUPPORTED_ERR); WebCore::ExceptionCode ec = 0; BOOL result = WebCore::EventTargetNodeCast([self _node])->dispatchEvent([event _event], ec); WebCore::raiseOnDOMError(ec); return result; } @end //------------------------------------------------------------------------------------------ // DOMElement // FIXME: this should be auto-generated in DOMElement.mm @implementation DOMElement (DOMElementAppKitExtensions) // FIXME: this should be implemented in the implementation - (NSImage*)image { WebCore::RenderObject* renderer = [self _element]->renderer(); if (renderer && renderer->isImage()) { WebCore::RenderImage* img = static_cast(renderer); if (img->cachedImage() && !img->cachedImage()->errorOccurred()) return img->cachedImage()->image()->getNSImage(); } return nil; } @end @implementation DOMElement (WebPrivate) // FIXME: this should be implemented in the implementation - (NSFont *)_font { WebCore::RenderObject* renderer = [self _element]->renderer(); if (renderer) return renderer->style()->font().primaryFont()->getNSFont(); return nil; } // FIXME: this should be implemented in the implementation - (NSData *)_imageTIFFRepresentation { WebCore::RenderObject* renderer = [self _element]->renderer(); if (renderer && renderer->isImage()) { WebCore::RenderImage* img = static_cast(renderer); if (img->cachedImage() && !img->cachedImage()->errorOccurred()) return (NSData*)(img->cachedImage()->image()->getTIFFRepresentation()); } return nil; } - (NSRect)_windowClipRect { WebCore::RenderObject* renderer = [self _element]->renderer(); if (renderer && renderer->view()) { WebCore::FrameView* frameView = renderer->view()->frameView(); if (!frameView) return WebCore::IntRect(); return frameView->windowClipRectForLayer(renderer->enclosingLayer(), true); } return WebCore::IntRect(); } // FIXME: this should be implemented in the implementation - (NSURL *)_getURLAttribute:(NSString *)name { ASSERT(name); WebCore::Element* element = [self _element]; ASSERT(element); return WebCore::KURL(element->document()->completeURL(parseURL(element->getAttribute(name)).deprecatedString())).getNSURL(); } // FIXME: this should be implemented in the implementation - (void *)_NPObject { WebCore::Element* element = [self _element]; if (element->hasTagName(WebCore::HTMLNames::appletTag) || element->hasTagName(WebCore::HTMLNames::embedTag) || element->hasTagName(WebCore::HTMLNames::objectTag)) return static_cast(element)->getNPObject(); return 0; } // FIXME: this should be implemented in the implementation - (BOOL)isFocused { WebCore::Element* impl = [self _element]; if (impl->document()->focusedNode() == impl) return YES; return NO; } @end //------------------------------------------------------------------------------------------ // DOMRange @implementation DOMRange (WebPrivate) - (NSString *)description { if (!_internal) return @""; return [NSString stringWithFormat:@"", [self startContainer], [self startOffset], [self endContainer], [self endOffset]]; } // FIXME: this should be removed as soon as all internal Apple uses of it have been replaced with // calls to the public method - (NSString *)text. - (NSString *)_text { return [self text]; } @end //------------------------------------------------------------------------------------------ // DOMNodeFilter // FIXME: This implementation should be in it's own file. @implementation DOMNodeFilter - (id)_initWithNodeFilter:(WebCore::NodeFilter *)impl { ASSERT(impl); [super _init]; _internal = reinterpret_cast(impl); impl->ref(); WebCore::addDOMWrapper(self, impl); return self; } + (DOMNodeFilter *)_wrapNodeFilter:(WebCore::NodeFilter *)impl { if (!impl) return nil; id cachedInstance; cachedInstance = WebCore::getDOMWrapper(impl); if (cachedInstance) return [[cachedInstance retain] autorelease]; return [[[self alloc] _initWithNodeFilter:impl] autorelease]; } - (WebCore::NodeFilter *)_nodeFilter { return reinterpret_cast(_internal); } - (void)dealloc { if (_internal) reinterpret_cast(_internal)->deref(); [super dealloc]; } - (void)finalize { if (_internal) reinterpret_cast(_internal)->deref(); [super finalize]; } - (short)acceptNode:(DOMNode *)node { return [self _nodeFilter]->acceptNode([node _node]); } @end //------------------------------------------------------------------------------------------ // ObjCNodeFilterCondition class ObjCNodeFilterCondition : public WebCore::NodeFilterCondition { public: ObjCNodeFilterCondition(id ); virtual ~ObjCNodeFilterCondition(); virtual short acceptNode(WebCore::Node*) const; private: ObjCNodeFilterCondition(const ObjCNodeFilterCondition&); ObjCNodeFilterCondition &operator=(const ObjCNodeFilterCondition&); id m_filter; }; ObjCNodeFilterCondition::ObjCNodeFilterCondition(id filter) : m_filter(filter) { ASSERT(m_filter); HardRetain(m_filter); } ObjCNodeFilterCondition::~ObjCNodeFilterCondition() { HardRelease(m_filter); } short ObjCNodeFilterCondition::acceptNode(WebCore::Node* node) const { if (!node) return WebCore::NodeFilter::FILTER_REJECT; return [m_filter acceptNode:[DOMNode _wrapNode:node]]; } //------------------------------------------------------------------------------------------ // DOMDocument (DOMDocumentTraversal) // FIXME: this should be auto-generated in DOMDocument.mm @implementation DOMDocument (DOMDocumentTraversal) - (DOMNodeIterator *)createNodeIterator:(DOMNode *)root whatToShow:(unsigned)whatToShow filter:(id )filter expandEntityReferences:(BOOL)expandEntityReferences { WebCore::NodeFilter* cppFilter = 0; if (filter) cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter)); WebCore::ExceptionCode ec = 0; RefPtr impl = [self _document]->createNodeIterator([root _node], whatToShow, cppFilter, expandEntityReferences, ec); WebCore::raiseOnDOMError(ec); return [DOMNodeIterator _wrapNodeIterator:impl.get() filter:filter]; } - (DOMTreeWalker *)createTreeWalker:(DOMNode *)root whatToShow:(unsigned)whatToShow filter:(id )filter expandEntityReferences:(BOOL)expandEntityReferences { WebCore::NodeFilter* cppFilter = 0; if (filter) cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter)); WebCore::ExceptionCode ec = 0; RefPtr impl = [self _document]->createTreeWalker([root _node], whatToShow, cppFilter, expandEntityReferences, ec); WebCore::raiseOnDOMError(ec); return [DOMTreeWalker _wrapTreeWalker:impl.get() filter:filter]; } @end @implementation DOMDocument (DOMDocumentTraversalDeprecated) - (DOMNodeIterator *)createNodeIterator:(DOMNode *)root :(unsigned)whatToShow :(id )filter :(BOOL)expandEntityReferences { return [self createNodeIterator:root whatToShow:whatToShow filter:filter expandEntityReferences:expandEntityReferences]; } - (DOMTreeWalker *)createTreeWalker:(DOMNode *)root :(unsigned)whatToShow :(id )filter :(BOOL)expandEntityReferences { return [self createTreeWalker:root whatToShow:whatToShow filter:filter expandEntityReferences:expandEntityReferences]; } @end //------------------------------------------------------------------------------------------ // ObjCEventListener namespace WebCore { ObjCEventListener* ObjCEventListener::find(id listener) { if (ListenerMap* map = listenerMap) return map->get(listener); return 0; } ObjCEventListener *ObjCEventListener::create(id listener) { ObjCEventListener* wrapper = find(listener); if (!wrapper) wrapper = new ObjCEventListener(listener); wrapper->ref(); return wrapper; } ObjCEventListener::ObjCEventListener(id listener) : m_listener([listener retain]) { ListenerMap* map = listenerMap; if (!map) { map = new ListenerMap; listenerMap = map; } map->set(listener, this); } ObjCEventListener::~ObjCEventListener() { listenerMap->remove(m_listener); [m_listener release]; } void ObjCEventListener::handleEvent(Event* event, bool) { [m_listener handleEvent:[DOMEvent _wrapEvent:event]]; } } // namespace WebCore