DOM.mm   [plain text]


/*
 * Copyright (C) 2004-2006 Apple Computer, Inc.  All rights reserved.
 * Copyright (C) 2006 James G. Speth (speth@end.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 "DOMEventsInternal.h"
#import "DOMImplementationFront.h"
#import "DOMInternal.h"
#import "DOMPrivate.h"
#import "Document.h"
#import "DocumentFragment.h"
#import "DocumentType.h"
#import "Entity.h"
#import "EntityReference.h"
#import "Event.h"
#import "EventListener.h"
#import "FoundationExtras.h"
#import "FrameMac.h"
#import "HTMLInputElement.h"
#import "HTMLDocument.h"
#import "HTMLNames.h"
#import "HTMLPlugInElement.h"
#import "NodeFilter.h"
#import "NodeFilterCondition.h"
#import "NodeIterator.h"
#import "NodeList.h"
#import "Notation.h"
#import "ProcessingInstruction.h"
#import "QualifiedName.h"
#import "Range.h"
#import "RenderBlock.h"
#import "RenderImage.h"
#import "TreeWalker.h"
#import "WebScriptObjectPrivate.h"
#import <objc/objc-class.h>

#import "WAKAppKitStubs.h"
#import "WAKWindow.h"
#import "WebCoreFrameBridge.h"
#import "WebCoreThreadMessage.h"
#import "WKWindowPrivate.h"
#import "ThreadSafeWrapper.h"

using WebCore::AtomicString;
using WebCore::AtomicStringImpl;
using WebCore::Attr;
using WebCore::CharacterData;
using WebCore::DeprecatedValueList;
using WebCore::Document;
using WebCore::DocumentFragment;
using WebCore::DocumentType;
using WebCore::DOMImplementationFront;
using WebCore::Element;
using WebCore::Entity;
using WebCore::Event;
using WebCore::EventListener;
using WebCore::ExceptionCode;
using WebCore::HTMLDocument;
using WebCore::HTMLElement;
using WebCore::HTMLInputElement;
using WebCore::FrameMac;
using WebCore::IntRect;
using WebCore::KURL;
using WebCore::NamedNodeMap;
using WebCore::Node;
using WebCore::NodeFilter;
using WebCore::NodeFilterCondition;
using WebCore::NodeIterator;
using WebCore::NodeList;
using WebCore::Notation;
using WebCore::ProcessingInstruction;
using WebCore::QualifiedName;
using WebCore::Range;
using WebCore::RenderBlock;
using WebCore::RenderImage;
using WebCore::RenderObject;
using WebCore::String;
using WebCore::Text;
using WebCore::TreeWalker;

using WebCore::RenderStyle;

using namespace WebCore::HTMLNames;

@interface DOMAttr (WebCoreInternal)
+ (DOMAttr *)_attrWith:(Attr *)impl;
- (Attr *)_attr;
@end

@interface DOMDocumentType (WebCoreInternal)
- (DocumentType *)_documentType;
@end

@interface DOMImplementation (WebCoreInternal)
+ (DOMImplementation *)_DOMImplementationWith:(DOMImplementationFront *)impl;
- (DOMImplementationFront *)_DOMImplementation;
@end

class ObjCEventListener : public EventListener {
public:
    static ObjCEventListener *find(id <DOMEventListener>);
    static ObjCEventListener *create(id <DOMEventListener>);

private:
    ObjCEventListener(id <DOMEventListener>);
    virtual ~ObjCEventListener();

    virtual void handleEvent(Event *, bool isWindowEvent);

    id <DOMEventListener> m_listener;
};

typedef HashMap<id, ObjCEventListener*> ListenerMap;
typedef HashMap<AtomicStringImpl*, Class> ObjCClassMap;

static ObjCClassMap* elementClassMap;
static ListenerMap* listenerMap;

//------------------------------------------------------------------------------------------
// DOMObject

@implementation DOMObject

// Prevent creation of DOM objects by clients who just "[[xxx alloc] init]".
- (id)init
{
    [NSException raise:NSGenericException format:@"+[%@ init]: should never be used", NSStringFromClass([self class])];
    [self release];
    return nil;
}

- (void)dealloc
{
    if (_internal) {
        removeDOMWrapper(_internal);
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        removeDOMWrapper(_internal);
    }
    [super finalize];
}

- (id)copyWithZone:(NSZone *)zone
{
    return [self retain];
}

@end

@implementation DOMObject (WebCoreInternal)

- (id)_init
{
    return [super _init];
}

- (void)release 
{ 
    WebThreadAdoptAndReleaseIfNeeded 
    [super release];
}

@end

//------------------------------------------------------------------------------------------
// DOMNode

@implementation DOMNode

- (void)dealloc
{
    if (_internal) {
        DOM_cast<Node *>(_internal)->deref();
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        DOM_cast<Node *>(_internal)->deref();
    }
    [super finalize];
}

- (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];
}

- (NSString *)nodeName
{
    return [self _node]->nodeName();
}

- (NSString *)nodeValue
{
    // Documentation says we can raise a DOMSTRING_SIZE_ERR.
    // However, the lower layer does not report that error up to us.
    return [self _node]->nodeValue();
}

- (void)setNodeValue:(NSString *)string
{
    ASSERT(string);
    
    ExceptionCode ec = 0;
    [self _node]->setNodeValue(string, ec);
    raiseOnDOMError(ec);
}

- (unsigned short)nodeType
{
    return [self _node]->nodeType();
}

- (DOMNode *)parentNode
{
    return [DOMNode _nodeWith:[self _node]->parentNode()];
}

- (DOMNodeList *)childNodes
{
    return [DOMNodeList _nodeListWith:[self _node]->childNodes().get()];
}

- (DOMNode *)firstChild
{
    return [DOMNode _nodeWith:[self _node]->firstChild()];
}

- (DOMNode *)lastChild
{
    return [DOMNode _nodeWith:[self _node]->lastChild()];
}

- (DOMNode *)previousSibling
{
    return [DOMNode _nodeWith:[self _node]->previousSibling()];
}

- (DOMNode *)nextSibling
{
    return [DOMNode _nodeWith:[self _node]->nextSibling()];
}

- (DOMNamedNodeMap *)attributes
{
    // DOM level 2 core specification says: 
    // A NamedNodeMap containing the attributes of this node (if it is an Element) or null otherwise.
    return nil;
}

- (DOMDocument *)ownerDocument
{
    return [DOMDocument _documentWith:[self _node]->document()];
}

- (DOMNode *)insertBefore:(DOMNode *)newChild :(DOMNode *)refChild
{
    ASSERT(newChild);
    ASSERT(refChild);

    ExceptionCode ec = 0;
    if ([self _node]->insertBefore([newChild _node], [refChild _node], ec))
        return newChild;
    raiseOnDOMError(ec);
    return nil;
}

- (DOMNode *)replaceChild:(DOMNode *)newChild :(DOMNode *)oldChild
{
    ASSERT(newChild);
    ASSERT(oldChild);

    ExceptionCode ec = 0;
    if ([self _node]->replaceChild([newChild _node], [oldChild _node], ec))
        return oldChild;
    raiseOnDOMError(ec);
    return nil;
}

- (DOMNode *)removeChild:(DOMNode *)oldChild
{
    ASSERT(oldChild);

    ExceptionCode ec = 0;
    if ([self _node]->removeChild([oldChild _node], ec))
        return oldChild;
    raiseOnDOMError(ec);
    return nil;
}

- (DOMNode *)appendChild:(DOMNode *)newChild
{
    ASSERT(newChild);

    ExceptionCode ec = 0;
    if ([self _node]->appendChild([newChild _node], ec))
        return newChild;
    raiseOnDOMError(ec);
    return nil;
}

- (BOOL)hasChildNodes
{
    return [self _node]->hasChildNodes();
}

- (DOMNode *)cloneNode:(BOOL)deep
{
    return [DOMNode _nodeWith:[self _node]->cloneNode(deep).get()];
}

- (void)normalize
{
    [self _node]->normalize();
}

- (BOOL)isSupported:(NSString *)feature :(NSString *)version
{
    ASSERT(feature);
    ASSERT(version);

    return [self _node]->isSupported(feature, version);
}

- (NSString *)namespaceURI
{
    return [self _node]->namespaceURI();
}

- (NSString *)prefix
{
    return [self _node]->prefix();
}

- (void)setPrefix:(NSString *)prefix
{
    ASSERT(prefix);

    ExceptionCode ec = 0;
    String prefixStr(prefix);
    [self _node]->setPrefix(prefixStr.impl(), ec);
    raiseOnDOMError(ec);
}

- (NSString *)localName
{
    return [self _node]->localName();
}

- (BOOL)hasAttributes
{
    return [self _node]->hasAttributes();
}

- (BOOL)isSameNode:(DOMNode *)other
{
    return [self _node]->isSameNode([other _node]);
}

- (BOOL)isEqualNode:(DOMNode *)other
{
    return [self _node]->isEqualNode([other _node]);
}

- (BOOL)isDefaultNamespace:(NSString *)namespaceURI
{
    return [self _node]->isDefaultNamespace(namespaceURI);
}

- (NSString *)lookupPrefix:(NSString *)namespaceURI
{
    return [self _node]->lookupPrefix(namespaceURI);
}

- (NSString *)lookupNamespaceURI:(NSString *)prefix
{
    return [self _node]->lookupNamespaceURI(prefix);
}

- (NSString *)textContent
{
    return [self _node]->textContent();
}

- (void)setTextContent:(NSString *)text
{
    ExceptionCode ec = 0;
    [self _node]->setTextContent(text, ec);
    raiseOnDOMError(ec);
}

- (NSRect)boundingBox
{
    WebCore::RenderObject *renderer = [self _node]->renderer();
    if (renderer)
        return renderer->absoluteBoundingBoxRect();
    return NSZeroRect;
}

- (NSArray *)lineBoxRects
{
    WebCore::RenderObject *renderer = [self _node]->renderer();
    if (renderer) {
        NSMutableArray *results = [[NSMutableArray alloc] init];
        DeprecatedValueList<IntRect> rects = renderer->lineBoxRects();
        if (!rects.isEmpty()) {
            for (DeprecatedValueList<IntRect>::ConstIterator it = rects.begin(); it != rects.end(); ++it)
                [results addObject:[NSValue valueWithRect:CGRectMake((*it).x(), (*it).y(), (*it).width(), (*it).height())]];
        }
        return [results autorelease];
    }
    return nil;
}


- (DOMElement *)rootEditableElement
{
    Element *element = [self _node]->rootEditableElement();
    return element ? [DOMElement _elementWith:element] : nil;    
    //if we ever need a wrapper of a more specific class, consider this: 
    //return static_cast<DOMElement *>([DOMNode _nodeWithImpl:[self _nodeImpl]->rootEditableElement()]);
}

- (Element *)_cachedLink
{
    if(!_link)
    {
        WebCore::Node* node= [self _node];
    
        do { if(node->isLink()) return static_cast<Element*>(_link= node); }
        while((node= node->parentNode()));
    }
    
    return static_cast<Element *>(_link);
}
- (NSURL *)hrefURL
{
    Element *link= [self _cachedLink];
    
    if(link) return KURL(link->document()->completeURL(parseURL(link->getAttribute("href")).deprecatedString())).getNSURL();
    
    return nil;
}

- (CGRect)hrefFrame
{
    RenderObject *renderer = [self _cachedLink]->renderer();
    
    if(renderer) return renderer->absoluteBoundingBoxRect();
    
    return NSZeroRect;
}

- (NSString *)hrefLabel
{
    Element *link= [self _cachedLink];
    
    if (!link) return nil;

    return link->textContent();
}

- (NSString *)hrefTitle
{
    Element *link= [self _cachedLink];
    
    if (!link) return nil;
    
    return static_cast<HTMLElement *>(link)->title().replace('\\', link->document()->backslashAsCurrencySymbol());
}

- (CGRect)boundingFrame
{
    return [self boundingBox];
}

- (CGRect)innerFrame
{
	Node * node = [self _node];
	RenderObject * renderer = node->renderer();
	
	if (!renderer) return CGRectZero;

	RenderStyle * style = renderer->style();
	CGRect innerFrame = [self boundingFrame];
	
	innerFrame.origin.x += style->borderLeftWidth();
	innerFrame.size.width -= style->borderLeftWidth() + style->borderRightWidth();

	innerFrame.origin.y += style->borderBottomWidth();
	innerFrame.size.height -= style->borderBottomWidth() + style->borderTopWidth();
	
	return innerFrame;
}

- (float)computedFontSize
{
    return [self _node]->renderStyle()->fontDescription().computedSize();
}

- (void)simulateCompleteClick
{
    APPLY_ON_WEBTHREAD {
    
        HTMLElement *targetElement= nil;

        // We can only simulate a complete click if we are an HTML Element ourselves...
        if([self isKindOfClass: [DOMHTMLElement class]]) targetElement= static_cast<HTMLElement *>([self _node]);
        // Or if we have a parent HTML Element link.
        else if([self _cachedLink] && [[DOMNode _nodeWith: [self _cachedLink]] isKindOfClass: [DOMHTMLElement class]]) targetElement= static_cast<HTMLElement *>([self _cachedLink]);
        // If neither is true, then simply return.
        else return;

        targetElement->click(YES, NO);
    }
}

- (DOMNode *)nextFocusNode
{
    return [DOMNode _nodeWith:[self _node]->document()->nextFocusNode([self _node])];
}

- (DOMNode *)previousFocusNode
{
    return [DOMNode _nodeWith:[self _node]->document()->previousFocusNode([self _node])];
}


@end

static void addElementClass(const QualifiedName& tag, Class objCClass)
{
    elementClassMap->set(tag.localName().impl(), objCClass);
}

static void createHTMLElementClassMap()
{
    // Create the table.
    elementClassMap = new ObjCClassMap;
    
    // Populate it with HTML element classes.
    addElementClass(aTag, [DOMHTMLAnchorElement class]);
    addElementClass(appletTag, [DOMHTMLAppletElement class]);
    addElementClass(areaTag, [DOMHTMLAreaElement class]);
    addElementClass(baseTag, [DOMHTMLBaseElement class]);
    addElementClass(basefontTag, [DOMHTMLBaseFontElement class]);
    addElementClass(bodyTag, [DOMHTMLBodyElement class]);
    addElementClass(brTag, [DOMHTMLBRElement class]);
    addElementClass(buttonTag, [DOMHTMLButtonElement class]);
    addElementClass(canvasTag, [DOMHTMLImageElement class]);
    addElementClass(captionTag, [DOMHTMLTableCaptionElement class]);
    addElementClass(colTag, [DOMHTMLTableColElement class]);
    addElementClass(colgroupTag, [DOMHTMLTableColElement class]);
    addElementClass(dirTag, [DOMHTMLDirectoryElement class]);
    addElementClass(divTag, [DOMHTMLDivElement class]);
    addElementClass(dlTag, [DOMHTMLDListElement class]);
    addElementClass(embedTag, [DOMHTMLEmbedElement class]);
    addElementClass(fieldsetTag, [DOMHTMLFieldSetElement class]);
    addElementClass(fontTag, [DOMHTMLFontElement class]);
    addElementClass(formTag, [DOMHTMLFormElement class]);
    addElementClass(frameTag, [DOMHTMLFrameElement class]);
    addElementClass(framesetTag, [DOMHTMLFrameSetElement class]);
    addElementClass(h1Tag, [DOMHTMLHeadingElement class]);
    addElementClass(h2Tag, [DOMHTMLHeadingElement class]);
    addElementClass(h3Tag, [DOMHTMLHeadingElement class]);
    addElementClass(h4Tag, [DOMHTMLHeadingElement class]);
    addElementClass(h5Tag, [DOMHTMLHeadingElement class]);
    addElementClass(h6Tag, [DOMHTMLHeadingElement class]);
    addElementClass(headTag, [DOMHTMLHeadElement class]);
    addElementClass(hrTag, [DOMHTMLHRElement class]);
    addElementClass(htmlTag, [DOMHTMLHtmlElement class]);
    addElementClass(iframeTag, [DOMHTMLIFrameElement class]);
    addElementClass(imgTag, [DOMHTMLImageElement class]);
    addElementClass(inputTag, [DOMHTMLInputElement class]);
    addElementClass(isindexTag, [DOMHTMLIsIndexElement class]);
    addElementClass(labelTag, [DOMHTMLLabelElement class]);
    addElementClass(legendTag, [DOMHTMLLegendElement class]);
    addElementClass(liTag, [DOMHTMLLIElement class]);
    addElementClass(linkTag, [DOMHTMLLinkElement class]);
    addElementClass(listingTag, [DOMHTMLPreElement class]);
    addElementClass(mapTag, [DOMHTMLMapElement class]);
    addElementClass(menuTag, [DOMHTMLMenuElement class]);
    addElementClass(metaTag, [DOMHTMLMetaElement class]);
    addElementClass(objectTag, [DOMHTMLObjectElement class]);
    addElementClass(olTag, [DOMHTMLOListElement class]);
    addElementClass(optgroupTag, [DOMHTMLOptGroupElement class]);
    addElementClass(optionTag, [DOMHTMLOptionElement class]);
    addElementClass(pTag, [DOMHTMLParagraphElement class]);
    addElementClass(paramTag, [DOMHTMLParamElement class]);
    addElementClass(preTag, [DOMHTMLPreElement class]);
    addElementClass(qTag, [DOMHTMLQuoteElement class]);
    addElementClass(scriptTag, [DOMHTMLScriptElement class]);
    addElementClass(selectTag, [DOMHTMLSelectElement class]);
    addElementClass(styleTag, [DOMHTMLStyleElement class]);
    addElementClass(tableTag, [DOMHTMLTableElement class]);
    addElementClass(tbodyTag, [DOMHTMLTableSectionElement class]);
    addElementClass(tdTag, [DOMHTMLTableCellElement class]);
    addElementClass(textareaTag, [DOMHTMLTextAreaElement class]);
    addElementClass(tfootTag, [DOMHTMLTableSectionElement class]);
    addElementClass(theadTag, [DOMHTMLTableSectionElement class]);
    addElementClass(titleTag, [DOMHTMLTitleElement class]);
    addElementClass(trTag, [DOMHTMLTableRowElement class]);
    addElementClass(ulTag, [DOMHTMLUListElement class]);

    // FIXME: Reflect marquee once the API has been determined.
}

static Class elementClass(const AtomicString& tagName)
{
    if (!elementClassMap)
        createHTMLElementClassMap();
    Class objcClass = elementClassMap->get(tagName.impl());
    if (!objcClass)
        objcClass = [DOMHTMLElement class];
    return objcClass;
}

@implementation DOMNode (WebCoreInternal)

- (id)_initWithNode:(Node *)impl
{
    ASSERT(impl);
    
    [super _init];
    
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    return self;
}

+ (DOMNode *)_nodeWith:(Node *)impl
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    Class wrapperClass = nil;
    switch (impl->nodeType()) {
        case Node::ELEMENT_NODE:
            if (impl->isHTMLElement())
                wrapperClass = elementClass(static_cast<HTMLElement*>(impl)->localName());
            else
                wrapperClass = [DOMElement class];
            break;
        case Node::ATTRIBUTE_NODE:
            wrapperClass = [DOMAttr class];
            break;
        case Node::TEXT_NODE:
            wrapperClass = [DOMText class];
            break;
        case Node::CDATA_SECTION_NODE:
            wrapperClass = [DOMCDATASection class];
            break;
        case Node::ENTITY_REFERENCE_NODE:
            wrapperClass = [DOMEntityReference class];
            break;
        case Node::ENTITY_NODE:
            wrapperClass = [DOMEntity class];
            break;
        case Node::PROCESSING_INSTRUCTION_NODE:
            wrapperClass = [DOMProcessingInstruction class];
            break;
        case Node::COMMENT_NODE:
            wrapperClass = [DOMComment class];
            break;
        case Node::DOCUMENT_NODE:
            if (static_cast<Document*>(impl)->isHTMLDocument())
                wrapperClass = [DOMHTMLDocument class];
            else
                wrapperClass = [DOMDocument class];
            break;
        case Node::DOCUMENT_TYPE_NODE:
            wrapperClass = [DOMDocumentType class];
            break;
        case Node::DOCUMENT_FRAGMENT_NODE:
            wrapperClass = [DOMDocumentFragment class];
            break;
        case Node::NOTATION_NODE:
            wrapperClass = [DOMNotation class];
            break;
        case Node::XPATH_NAMESPACE_NODE:
            // FIXME: Create an XPath objective C wrapper
            // See http://bugzilla.opendarwin.org/show_bug.cgi?id=8755
            return nil;
    }
    return [[[wrapperClass alloc] _initWithNode:impl] autorelease];
}

- (Node *)_node
{
    return DOM_cast<Node *>(_internal);
}

- (BOOL)isContentEditable
{
    return [self _node]->isContentEditable();
}

- (const KJS::Bindings::RootObject *)_executionContext
{
    if (Node *n = [self _node])
        if (FrameMac *f = Mac(n->document()->frame()))
            return f->executionContextForDOM();

    return 0;
}

@end

@implementation DOMNode (DOMEventTarget)

- (void)addEventListener:(NSString *)type :(id <DOMEventListener>)listener :(BOOL)useCapture
{
    if (![self _node]->isEventTargetNode()) {
        NSLog(@"%@ addEventListener %@ for %@", self, type, listener);
        raiseDOMException(DOM_NOT_SUPPORTED_ERR);
    }
    
    EventListener *wrapper = ObjCEventListener::create(listener);
    EventTargetNodeCast([self _node])->addEventListener(type, wrapper, useCapture);
    wrapper->deref();
}

- (void)removeEventListener:(NSString *)type :(id <DOMEventListener>)listener :(BOOL)useCapture
{
    if (![self _node]->isEventTargetNode()) {
        NSLog(@"%@ removeEventListener %@ for %@", self, type, listener);
        raiseDOMException(DOM_NOT_SUPPORTED_ERR);
    }

    if (EventListener *wrapper = ObjCEventListener::find(listener))
        EventTargetNodeCast([self _node])->removeEventListener(type, wrapper, useCapture);
}
@end

//------------------------------------------------------------------------------------------
// DOMNamedNodeMap

@implementation DOMNamedNodeMap

- (void)dealloc
{
    if (_internal) {
        DOM_cast<NamedNodeMap *>(_internal)->deref();
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        DOM_cast<NamedNodeMap *>(_internal)->deref();
    }
    [super finalize];
}

- (NamedNodeMap *)_namedNodeMap
{
    return DOM_cast<NamedNodeMap *>(_internal);
}

- (DOMNode *)getNamedItem:(NSString *)name
{
    ASSERT(name);

    return [DOMNode _nodeWith:[self _namedNodeMap]->getNamedItem(name).get()];
}

- (DOMNode *)setNamedItem:(DOMNode *)arg
{
    ASSERT(arg);

    int exception = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _namedNodeMap]->setNamedItem([arg _node], exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMNode *)removeNamedItem:(NSString *)name
{
    ASSERT(name);

    int exception = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _namedNodeMap]->removeNamedItem(name, exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMNode *)item:(unsigned)index
{
    return [DOMNode _nodeWith:[self _namedNodeMap]->item(index).get()];
}

- (unsigned)length
{
    return [self _namedNodeMap]->length();
}

- (DOMNode *)getNamedItemNS:(NSString *)namespaceURI :(NSString *)localName
{
    if (!namespaceURI || !localName) {
        return nil;
    }

    return [DOMNode _nodeWith:[self _namedNodeMap]->getNamedItemNS(namespaceURI, localName).get()];
}

- (DOMNode *)setNamedItemNS:(DOMNode *)arg
{
    ASSERT(arg);

    int exception = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _namedNodeMap]->setNamedItemNS([arg _node], exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMNode *)removeNamedItemNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    int exception = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _namedNodeMap]->removeNamedItemNS(namespaceURI, localName, exception).get()];
    raiseOnDOMError(exception);
    return result;
}

@end

@implementation DOMNamedNodeMap (WebCoreInternal)

- (id)_initWithNamedNodeMap:(NamedNodeMap *)impl
{
    ASSERT(impl);

    [super _init];
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    return self;
}

+ (DOMNamedNodeMap *)_namedNodeMapWith:(NamedNodeMap *)impl
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithNamedNodeMap:impl] autorelease];
}

@end

//------------------------------------------------------------------------------------------
// DOMNodeList

@implementation DOMNodeList

- (void)dealloc
{
    if (_internal) {
        DOM_cast<NodeList *>(_internal)->deref();
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        DOM_cast<NodeList *>(_internal)->deref();
    }
    [super finalize];
}

- (NodeList *)_nodeList
{
    return DOM_cast<NodeList *>(_internal);
}

- (DOMNode *)item:(unsigned)index
{
    return [DOMNode _nodeWith:[self _nodeList]->item(index)];
}

- (unsigned)length
{
    return [self _nodeList]->length();
}

@end

@implementation DOMNodeList (WebCoreInternal)

- (id)_initWithNodeList:(NodeList *)impl
{
    ASSERT(impl);

    [super _init];
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    return self;
}

+ (DOMNodeList *)_nodeListWith:(NodeList *)impl
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithNodeList:impl] autorelease];
}

@end

//------------------------------------------------------------------------------------------
// DOMImplementation

@implementation DOMImplementation

- (void)dealloc
{
    if (_internal)
        DOM_cast<DOMImplementationFront *>(_internal)->deref();
    [super dealloc];
}

- (void)finalize
{
    if (_internal)
        DOM_cast<DOMImplementationFront *>(_internal)->deref();
    [super finalize];
}

- (BOOL)hasFeature:(NSString *)feature :(NSString *)version
{
    ASSERT(feature);
    ASSERT(version);

    return [self _DOMImplementation]->hasFeature(feature, version);
}

- (DOMDocumentType *)createDocumentType:(NSString *)qualifiedName :(NSString *)publicId :(NSString *)systemId
{
    ASSERT(qualifiedName);
    ASSERT(publicId);
    ASSERT(systemId);

    ExceptionCode ec = 0;
    RefPtr<DocumentType> impl = [self _DOMImplementation]->createDocumentType(qualifiedName, publicId, systemId, ec);
    raiseOnDOMError(ec);
    return static_cast<DOMDocumentType *>([DOMNode _nodeWith:impl.get()]);
}

- (DOMDocument *)createDocument:(NSString *)namespaceURI :(NSString *)qualifiedName :(DOMDocumentType *)doctype
{
    ASSERT(namespaceURI);
    ASSERT(qualifiedName);

    ExceptionCode ec = 0;
    RefPtr<Document> impl = [self _DOMImplementation]->createDocument(namespaceURI, qualifiedName, [doctype _documentType], ec);
    raiseOnDOMError(ec);
    return static_cast<DOMDocument *>([DOMNode _nodeWith:impl.get()]);
}

- (DOMHTMLDocument *)createHTMLDocument:(NSString *)title
{
    RefPtr<HTMLDocument> impl = [self _DOMImplementation]->createHTMLDocument(title);
    return static_cast<DOMHTMLDocument *>([DOMNode _nodeWith:impl.get()]);
}
@end

@implementation DOMImplementation (DOMImplementationCSS)

- (DOMCSSStyleSheet *)createCSSStyleSheet:(NSString *)title :(NSString *)media
{
    ASSERT(title);
    ASSERT(media);

    ExceptionCode ec = 0;
    DOMCSSStyleSheet *result = [DOMCSSStyleSheet _CSSStyleSheetWith:[self _DOMImplementation]->createCSSStyleSheet(title, media, ec).get()];
    raiseOnDOMError(ec);
    return result;
}

@end
 
@implementation DOMImplementation (WebCoreInternal)

- (id)_initWithDOMImplementation:(DOMImplementationFront *)impl
{
    ASSERT(impl);

    [super _init];
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    return self;
}

+ (DOMImplementation *)_DOMImplementationWith:(DOMImplementationFront *)impl
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithDOMImplementation:impl] autorelease];
}

- (DOMImplementationFront *)_DOMImplementation
{
    return DOM_cast<DOMImplementationFront *>(_internal);
}

@end

//------------------------------------------------------------------------------------------
// DOMDocumentFragment

@implementation DOMDocumentFragment

@end

@implementation DOMDocumentFragment (WebCoreInternal)

+ (DOMDocumentFragment *)_documentFragmentWith:(DocumentFragment *)impl
{
    return static_cast<DOMDocumentFragment *>([DOMNode _nodeWith:impl]);
}

- (DocumentFragment *)_fragment
{
    return static_cast<DocumentFragment *>(DOM_cast<Node *>(_internal));
}

@end

//------------------------------------------------------------------------------------------
// DOMDocument

@implementation DOMDocument

- (DOMNode *)adoptNode:(DOMNode *)source
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _document]->adoptNode([source _node], ec).get()];
    raiseOnDOMError(ec);
    return result;
}

- (DOMDocumentType *)doctype
{
    return static_cast<DOMDocumentType *>([DOMNode _nodeWith:[self _document]->doctype()]);
}

- (DOMImplementation *)implementation
{
    return [DOMImplementation _DOMImplementationWith:implementationFront([self _document])];
}

- (DOMElement *)documentElement
{
    return static_cast<DOMElement *>([DOMNode _nodeWith:[self _document]->documentElement()]);
}

- (DOMElement *)createElement:(NSString *)tagName
{
    ASSERT(tagName);

    ExceptionCode ec = 0;
    DOMElement *result = static_cast<DOMElement *>([DOMNode _nodeWith:[self _document]->createElement(tagName, ec).get()]);
    raiseOnDOMError(ec);
    return result;
}

- (DOMDocumentFragment *)createDocumentFragment
{
    return static_cast<DOMDocumentFragment *>([DOMNode _nodeWith:[self _document]->createDocumentFragment().get()]);
}

- (DOMText *)createTextNode:(NSString *)data
{
    ASSERT(data);
    return static_cast<DOMText *>([DOMNode _nodeWith:[self _document]->createTextNode(data).get()]);
}

- (DOMComment *)createComment:(NSString *)data
{
    ASSERT(data);
    return static_cast<DOMComment *>([DOMNode _nodeWith:[self _document]->createComment(data).get()]);
}

- (DOMCDATASection *)createCDATASection:(NSString *)data
{
    ASSERT(data);
    int exception = 0;
    DOMCDATASection *result = static_cast<DOMCDATASection *>([DOMNode _nodeWith:[self _document]->createCDATASection(data, exception).get()]);
    raiseOnDOMError(exception);
    return result;
}

- (DOMProcessingInstruction *)createProcessingInstruction:(NSString *)target :(NSString *)data
{
    ASSERT(target);
    ASSERT(data);
    int exception = 0;
    DOMProcessingInstruction *result = static_cast<DOMProcessingInstruction *>([DOMNode _nodeWith:[self _document]->createProcessingInstruction(target, data, exception).get()]);
    raiseOnDOMError(exception);
    return result;
}

- (DOMAttr *)createAttribute:(NSString *)name
{
    ASSERT(name);
    int exception = 0;
    DOMAttr *result = [DOMAttr _attrWith:[self _document]->createAttribute(name, exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMEntityReference *)createEntityReference:(NSString *)name
{
    ASSERT(name);
    int exception = 0;
    DOMEntityReference *result = static_cast<DOMEntityReference *>([DOMNode _nodeWith:[self _document]->createEntityReference(name, exception).get()]);
    raiseOnDOMError(exception);
    return result;
}

- (DOMNodeList *)getElementsByTagName:(NSString *)tagname
{
    ASSERT(tagname);
    return [DOMNodeList _nodeListWith:[self _document]->getElementsByTagName(tagname).get()];
}

- (DOMNode *)importNode:(DOMNode *)importedNode :(BOOL)deep
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _document]->importNode([importedNode _node], deep, ec).get()];
    raiseOnDOMError(ec);
    return result;
}

- (DOMElement *)createElementNS:(NSString *)namespaceURI :(NSString *)qualifiedName
{
    ASSERT(namespaceURI);
    ASSERT(qualifiedName);

    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _document]->createElementNS(namespaceURI, qualifiedName, ec).get()];
    raiseOnDOMError(ec);
    return static_cast<DOMElement *>(result);
}

- (DOMAttr *)createAttributeNS:(NSString *)namespaceURI :(NSString *)qualifiedName
{
    ASSERT(namespaceURI);
    ASSERT(qualifiedName);

    int exception = 0;
    DOMAttr *result = [DOMAttr _attrWith:[self _document]->createAttributeNS(namespaceURI, qualifiedName, exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMNodeList *)getElementsByTagNameNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    return [DOMNodeList _nodeListWith:[self _document]->getElementsByTagNameNS(namespaceURI, localName).get()];
}

- (DOMElement *)getElementById:(NSString *)elementId
{
    ASSERT(elementId);

    return static_cast<DOMElement *>([DOMNode _nodeWith:[self _document]->getElementById(elementId)]);
}

@end

@implementation DOMDocument (DOMDocumentRange)

- (DOMRange *)createRange
{
    return [DOMRange _rangeWith:[self _document]->createRange().get()];
}

@end

@implementation DOMDocument (DOMDocumentCSS)

- (DOMCSSStyleDeclaration *)getOverrideStyle:(DOMElement *)elt :(NSString *)pseudoElt
{
    Element *element = [elt _element];
    String pseudoEltString(pseudoElt);
    return [DOMCSSStyleDeclaration _styleDeclarationWith:[self _document]->getOverrideStyle(element, pseudoEltString.impl())];
}

@end

@implementation DOMDocument (DOMDocumentStyle)

- (DOMStyleSheetList *)styleSheets
{
    return [DOMStyleSheetList _styleSheetListWith:[self _document]->styleSheets()];
}

@end

@implementation DOMDocument (DOMDocumentExtensions)

- (DOMCSSStyleDeclaration *)createCSSStyleDeclaration
{
    return [DOMCSSStyleDeclaration _styleDeclarationWith:[self _document]->createCSSStyleDeclaration().get()];
}

@end

@implementation DOMDocument (WebCoreInternal)

+ (DOMDocument *)_documentWith:(Document *)impl
{
    return static_cast<DOMDocument *>([DOMNode _nodeWith:impl]);
}

- (Document *)_document
{
    return static_cast<Document *>(DOM_cast<Node *>(_internal));
}

- (DOMElement *)_ownerElement
{
    return [DOMElement _elementWith:[self _document]->ownerElement()];
}

@end

//------------------------------------------------------------------------------------------
// DOMCharacterData

@implementation DOMCharacterData

- (CharacterData *)_characterData
{
    return static_cast<CharacterData *>(DOM_cast<Node *>(_internal));
}

- (NSString *)data
{
    // Documentation says we can raise a DOMSTRING_SIZE_ERR.
    // However, the lower layer does not report that error up to us.
    return [self _characterData]->data();
}

- (void)setData:(NSString *)data
{
    ASSERT(data);
    
    ExceptionCode ec = 0;
    [self _characterData]->setData(data, ec);
    raiseOnDOMError(ec);
}

- (unsigned)length
{
    return [self _characterData]->length();
}

- (NSString *)substringData:(unsigned)offset :(unsigned)count
{
    ExceptionCode ec = 0;
    NSString *result = [self _characterData]->substringData(offset, count, ec);
    raiseOnDOMError(ec);
    return result;
}

- (void)appendData:(NSString *)arg
{
    ASSERT(arg);
    
    ExceptionCode ec = 0;
    [self _characterData]->appendData(arg, ec);
    raiseOnDOMError(ec);
}

- (void)insertData:(unsigned)offset :(NSString *)arg
{
    ASSERT(arg);
    
    ExceptionCode ec = 0;
    [self _characterData]->insertData(offset, arg, ec);
    raiseOnDOMError(ec);
}

- (void)deleteData:(unsigned)offset :(unsigned) count
{
    ExceptionCode ec = 0;
    [self _characterData]->deleteData(offset, count, ec);
    raiseOnDOMError(ec);
}

- (void)replaceData:(unsigned)offset :(unsigned)count :(NSString *)arg
{
    ASSERT(arg);

    ExceptionCode ec = 0;
    [self _characterData]->replaceData(offset, count, arg, ec);
    raiseOnDOMError(ec);
}

@end

//------------------------------------------------------------------------------------------
// DOMAttr

@implementation DOMAttr

- (NSString *)name
{
    return [self _attr]->nodeName();
}

- (BOOL)specified
{
    return [self _attr]->specified();
}

- (NSString *)value
{
    return [self _attr]->nodeValue();
}

- (void)setValue:(NSString *)value
{
    ASSERT(value);

    ExceptionCode ec = 0;
    [self _attr]->setValue(value, ec);
    raiseOnDOMError(ec);
}

- (DOMElement *)ownerElement
{
    return [DOMElement _elementWith:[self _attr]->ownerElement()];
}

- (DOMCSSStyleDeclaration *)style
{
    return [DOMCSSStyleDeclaration _styleDeclarationWith: [self _attr]->style()];
}

@end

@implementation DOMAttr (WebCoreInternal)

+ (DOMAttr *)_attrWith:(Attr *)impl
{
    return static_cast<DOMAttr *>([DOMNode _nodeWith:impl]);
}

- (Attr *)_attr
{
    return static_cast<Attr *>(DOM_cast<Node *>(_internal));
}

@end

//------------------------------------------------------------------------------------------
// DOMElement

@implementation DOMElement

- (NSString *)tagName
{
    return [self _element]->nodeName();
}

- (DOMNamedNodeMap *)attributes
{
    return [DOMNamedNodeMap _namedNodeMapWith:[self _element]->attributes()];
}

- (NSString *)getAttribute:(NSString *)name
{
    ASSERT(name);
    return [self _element]->getAttribute(name);
}

- (void)setAttribute:(NSString *)name :(NSString *)value
{
    ASSERT(name);
    ASSERT(value);

    int exception = 0;
    [self _element]->setAttribute(name, value, exception);
    raiseOnDOMError(exception);
}

- (void)removeAttribute:(NSString *)name
{
    ASSERT(name);

    int exception = 0;
    [self _element]->removeAttribute(name, exception);
    raiseOnDOMError(exception);
}

- (DOMAttr *)getAttributeNode:(NSString *)name
{
    ASSERT(name);

    return [DOMAttr _attrWith:[self _element]->getAttributeNode(name).get()];
}

- (DOMAttr *)setAttributeNode:(DOMAttr *)newAttr
{
    ASSERT(newAttr);

    int exception = 0;
    DOMAttr *result = [DOMAttr _attrWith:[self _element]->setAttributeNode([newAttr _attr], exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMAttr *)removeAttributeNode:(DOMAttr *)oldAttr
{
    ASSERT(oldAttr);

    int exception = 0;
    DOMAttr *result = [DOMAttr _attrWith:[self _element]->removeAttributeNode([oldAttr _attr], exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMNodeList *)getElementsByTagName:(NSString *)name
{
    ASSERT(name);

    return [DOMNodeList _nodeListWith:[self _element]->getElementsByTagName(name).get()];
}

- (NSString *)getAttributeNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    return [self _element]->getAttributeNS(namespaceURI, localName);
}

- (void)setAttributeNS:(NSString *)namespaceURI :(NSString *)qualifiedName :(NSString *)value
{
    ASSERT(namespaceURI);
    ASSERT(qualifiedName);
    ASSERT(value);

    int exception = 0;
    [self _element]->setAttributeNS(namespaceURI, qualifiedName, value, exception);
    raiseOnDOMError(exception);
}

- (void)removeAttributeNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    int exception = 0;
    [self _element]->removeAttributeNS(namespaceURI, localName, exception);
    raiseOnDOMError(exception);
}

- (DOMAttr *)getAttributeNodeNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    return [DOMAttr _attrWith:[self _element]->getAttributeNodeNS(namespaceURI, localName).get()];
}

- (DOMAttr *)setAttributeNodeNS:(DOMAttr *)newAttr
{
    ASSERT(newAttr);

    int exception = 0;
    DOMAttr *result = [DOMAttr _attrWith:[self _element]->setAttributeNodeNS([newAttr _attr], exception).get()];
    raiseOnDOMError(exception);
    return result;
}

- (DOMNodeList *)getElementsByTagNameNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    return [DOMNodeList _nodeListWith:[self _element]->getElementsByTagNameNS(namespaceURI, localName).get()];
}

- (BOOL)hasAttribute:(NSString *)name
{
    ASSERT(name);

    return [self _element]->hasAttribute(name);
}

- (BOOL)hasAttributeNS:(NSString *)namespaceURI :(NSString *)localName
{
    ASSERT(namespaceURI);
    ASSERT(localName);

    return [self _element]->hasAttributeNS(namespaceURI, localName);
}

- (void)focus
{
    APPLY_ON_WEBTHREAD
        [self _element]->focus();
}

- (void)blur
{
    APPLY_ON_WEBTHREAD
        [self _element]->blur();
}

@end

@implementation DOMElement (DOMElementCSSInlineStyle)

- (DOMCSSStyleDeclaration *)style
{
    return [DOMCSSStyleDeclaration _styleDeclarationWith:[self _element]->style()];
}

@end

@implementation DOMElement (DOMElementExtensions)


- (void)scrollIntoView:(BOOL)alignTop
{
    [self _element]->scrollIntoView(alignTop);
}

- (void)scrollIntoViewIfNeeded:(BOOL)centerIfNeeded
{
    [self _element]->scrollIntoViewIfNeeded(centerIfNeeded);
}

@end

@implementation DOMElement (WebCoreInternal)

+ (DOMElement *)_elementWith:(Element *)impl
{
    return static_cast<DOMElement *>([DOMNode _nodeWith:impl]);
}

- (Element *)_element
{
    return static_cast<Element *>(DOM_cast<Node *>(_internal));
}

@end

@implementation DOMElement (WebPrivate)

- (GSFontRef)_font
{
    RenderObject *renderer = [self _element]->renderer();
    if (renderer) {
        return renderer->style()->font().getFont();
    }
    return nil;
}

- (NSURL *)_getURLAttribute:(NSString *)name
{
    ASSERT(name);
    Element *e = [self _element];
    ASSERT(e);
    return KURL(e->document()->completeURL(parseURL(e->getAttribute(name)).deprecatedString())).getNSURL();
}


- (BOOL)isFocused
{
    Element* impl = [self _element];
    if (impl->document()->focusNode() == impl)
        return YES;
    return NO;
}

@end

//------------------------------------------------------------------------------------------
// DOMText

@implementation DOMText

- (Text *)_text
{
    return static_cast<Text *>(DOM_cast<Node *>(_internal));
}

- (DOMText *)splitText:(unsigned)offset
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _text]->splitText(offset, ec)];
    raiseOnDOMError(ec);
    return static_cast<DOMText *>(result);
}

@end

//------------------------------------------------------------------------------------------
// DOMComment

@implementation DOMComment

@end

//------------------------------------------------------------------------------------------
// DOMCDATASection

@implementation DOMCDATASection

@end

//------------------------------------------------------------------------------------------
// DOMDocumentType

@implementation DOMDocumentType

- (NSString *)name
{
    return [self _documentType]->publicId();
}

- (DOMNamedNodeMap *)entities
{
    return [DOMNamedNodeMap _namedNodeMapWith:[self _documentType]->entities()];
}

- (DOMNamedNodeMap *)notations
{
    return [DOMNamedNodeMap _namedNodeMapWith:[self _documentType]->notations()];
}

- (NSString *)publicId
{
    return [self _documentType]->publicId();
}

- (NSString *)systemId
{
    return [self _documentType]->systemId();
}

- (NSString *)internalSubset
{
    return [self _documentType]->internalSubset();
}

@end

@implementation DOMDocumentType (WebCoreInternal)

- (DocumentType *)_documentType
{
    return static_cast<DocumentType *>(DOM_cast<Node *>(_internal));
}

@end

//------------------------------------------------------------------------------------------
// DOMNotation

@implementation DOMNotation

- (Notation *)_notation
{
    return static_cast<Notation *>(DOM_cast<Node *>(_internal));
}

- (NSString *)publicId
{
    return [self _notation]->publicId();
}

- (NSString *)systemId
{
    return [self _notation]->systemId();
}

@end

//------------------------------------------------------------------------------------------
// DOMEntity

@implementation DOMEntity

- (Entity *)_entity
{
    return static_cast<Entity *>(DOM_cast<Node *>(_internal));
}

- (NSString *)publicId
{
    return [self _entity]->publicId();
}

- (NSString *)systemId
{
    return [self _entity]->systemId();
}

- (NSString *)notationName
{
    return [self _entity]->notationName();
}

@end

//------------------------------------------------------------------------------------------
// DOMEntityReference

@implementation DOMEntityReference

@end

//------------------------------------------------------------------------------------------
// DOMProcessingInstruction

@implementation DOMProcessingInstruction

- (ProcessingInstruction *)_processingInstruction
{
    return static_cast<ProcessingInstruction *>(DOM_cast<Node *>(_internal));
}

- (NSString *)target
{
    return [self _processingInstruction]->target();
}

- (NSString *)data
{
    return [self _processingInstruction]->data();
}

- (void)setData:(NSString *)data
{
    ASSERT(data);

    ExceptionCode ec = 0;
    [self _processingInstruction]->setData(data, ec);
    raiseOnDOMError(ec);
}

@end

//------------------------------------------------------------------------------------------
// DOMRange

@implementation DOMRange

- (void)dealloc
{
    if (_internal) {
        DOM_cast<Range *>(_internal)->deref();
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        DOM_cast<Range *>(_internal)->deref();
    }
    [super finalize];
}

- (NSString *)description
{
    if (!_internal)
        return @"<DOMRange: null>";
    return [NSString stringWithFormat:@"<DOMRange: %@ %d %@ %d>",
        [self startContainer], [self startOffset],
        [self endContainer], [self endOffset]];
}

- (DOMNode *)startContainer
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _range]->startContainer(ec)];
    raiseOnDOMError(ec);
    return result;
}

- (int)startOffset
{
    ExceptionCode ec = 0;
    int result = [self _range]->startOffset(ec);
    raiseOnDOMError(ec);
    return result;
}

- (DOMNode *)endContainer
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _range]->endContainer(ec)];
    raiseOnDOMError(ec);
    return result;
}

- (int)endOffset
{
    ExceptionCode ec = 0;
    int result = [self _range]->endOffset(ec);
    raiseOnDOMError(ec);
    return result;
}

- (BOOL)collapsed
{
    ExceptionCode ec = 0;
    BOOL result = [self _range]->collapsed(ec);
    raiseOnDOMError(ec);
    return result;
}

- (DOMNode *)commonAncestorContainer
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _range]->commonAncestorContainer(ec)];
    raiseOnDOMError(ec);
    return result;
}

- (void)setStart:(DOMNode *)refNode :(int)offset
{
    ExceptionCode ec = 0;
    [self _range]->setStart([refNode _node], offset, ec);
    raiseOnDOMError(ec);
}

- (void)setEnd:(DOMNode *)refNode :(int)offset
{
    ExceptionCode ec = 0;
    [self _range]->setEnd([refNode _node], offset, ec);
    raiseOnDOMError(ec);
}

- (void)setStartBefore:(DOMNode *)refNode
{
    ExceptionCode ec = 0;
    [self _range]->setStartBefore([refNode _node], ec);
    raiseOnDOMError(ec);
}

- (void)setStartAfter:(DOMNode *)refNode
{
    ExceptionCode ec = 0;
    [self _range]->setStartAfter([refNode _node], ec);
    raiseOnDOMError(ec);
}

- (void)setEndBefore:(DOMNode *)refNode
{
    ExceptionCode ec = 0;
    [self _range]->setEndBefore([refNode _node], ec);
    raiseOnDOMError(ec);
}

- (void)setEndAfter:(DOMNode *)refNode
{
    ExceptionCode ec = 0;
    [self _range]->setEndAfter([refNode _node], ec);
    raiseOnDOMError(ec);
}

- (void)collapse:(BOOL)toStart
{
    ExceptionCode ec = 0;
    [self _range]->collapse(toStart, ec);
    raiseOnDOMError(ec);
}

- (void)selectNode:(DOMNode *)refNode
{
    ExceptionCode ec = 0;
    [self _range]->selectNode([refNode _node], ec);
    raiseOnDOMError(ec);
}

- (void)selectNodeContents:(DOMNode *)refNode
{
    ExceptionCode ec = 0;
    [self _range]->selectNodeContents([refNode _node], ec);
    raiseOnDOMError(ec);
}

- (short)compareBoundaryPoints:(unsigned short)how :(DOMRange *)sourceRange
{
    ExceptionCode ec = 0;
    short result = [self _range]->compareBoundaryPoints(static_cast<Range::CompareHow>(how), [sourceRange _range], ec);
    raiseOnDOMError(ec);
    return result;
}

- (void)deleteContents
{
    ExceptionCode ec = 0;
    [self _range]->deleteContents(ec);
    raiseOnDOMError(ec);
}

- (DOMDocumentFragment *)extractContents
{
    ExceptionCode ec = 0;
    DOMDocumentFragment *result = [DOMDocumentFragment _documentFragmentWith:[self _range]->extractContents(ec).get()];
    raiseOnDOMError(ec);
    return result;
}

- (DOMDocumentFragment *)cloneContents
{
    ExceptionCode ec = 0;
    DOMDocumentFragment *result = [DOMDocumentFragment _documentFragmentWith:[self _range]->cloneContents(ec).get()];
    raiseOnDOMError(ec);
    return result;
}

- (void)insertNode:(DOMNode *)newNode
{
    ExceptionCode ec = 0;
    [self _range]->insertNode([newNode _node], ec);
    raiseOnDOMError(ec);
}

- (void)surroundContents:(DOMNode *)newParent
{
    ExceptionCode ec = 0;
    [self _range]->surroundContents([newParent _node], ec);
    raiseOnDOMError(ec);
}

- (DOMRange *)cloneRange
{
    ExceptionCode ec = 0;
    DOMRange *result = [DOMRange _rangeWith:[self _range]->cloneRange(ec).get()];
    raiseOnDOMError(ec);
    return result;
}

- (NSString *)toString
{
    ExceptionCode ec = 0;
    NSString *result = [self _range]->toString(ec);
    raiseOnDOMError(ec);
    return result;
}

- (NSString *)text
{
    return [self _range]->text();
}

- (void)detach
{
    ExceptionCode ec = 0;
    [self _range]->detach(ec);
    raiseOnDOMError(ec);
}

@end

@implementation DOMRange (WebCoreInternal)

- (id)_initWithRange:(Range *)impl
{
    ASSERT(impl);

    [super _init];
    
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    return self;
}

+ (DOMRange *)_rangeWith:(Range *)impl
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithRange:impl] autorelease];
}

- (Range *)_range
{
    return DOM_cast<Range *>(_internal);
}

@end

@implementation DOMRange (WebPrivate)

- (NSString *)_text
{
    return [self text];
}

@end

//------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------

@implementation DOMNodeFilter

- (id)_initWithNodeFilter:(NodeFilter *)impl
{
    ASSERT(impl);

    [super _init];
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    return self;
}

+ (DOMNodeFilter *)_nodeFilterWith:(NodeFilter *)impl
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithNodeFilter:impl] autorelease];
}

- (NodeFilter *)_nodeFilter
{
    return DOM_cast<NodeFilter *>(_internal);
}

- (void)dealloc
{
    if (_internal)
        DOM_cast<NodeFilter *>(_internal)->deref();
    [super dealloc];
}

- (void)finalize
{
    if (_internal)
        DOM_cast<NodeFilter *>(_internal)->deref();
    [super finalize];
}

- (short)acceptNode:(DOMNode *)node
{
    return [self _nodeFilter]->acceptNode([node _node]);
}

@end


@implementation DOMNodeIterator

- (id)_initWithNodeIterator:(NodeIterator *)impl filter:(id <DOMNodeFilter>)filter
{
    ASSERT(impl);

    [super _init];
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    m_filter = [filter retain];
    return self;
}

- (NodeIterator *)_nodeIterator
{
    return DOM_cast<NodeIterator *>(_internal);
}

- (void)dealloc
{
    [m_filter release];
    if (_internal) {
        [self detach];
        DOM_cast<NodeIterator *>(_internal)->deref();
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        [self detach];
        DOM_cast<NodeIterator *>(_internal)->deref();
    }
    [super finalize];
}

- (DOMNode *)root
{
    return [DOMNode _nodeWith:[self _nodeIterator]->root()];
}

- (unsigned)whatToShow
{
    return [self _nodeIterator]->whatToShow();
}

- (id <DOMNodeFilter>)filter
{
    if (m_filter)
        // This node iterator was created from the objc side
        return [[m_filter retain] autorelease];

    // This node iterator was created from the c++ side
    return [DOMNodeFilter _nodeFilterWith:[self _nodeIterator]->filter()];
}

- (BOOL)expandEntityReferences
{
    return [self _nodeIterator]->expandEntityReferences();
}

- (DOMNode *)nextNode
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _nodeIterator]->nextNode(ec)];
    raiseOnDOMError(ec);
    return result;
}

- (DOMNode *)previousNode
{
    ExceptionCode ec = 0;
    DOMNode *result = [DOMNode _nodeWith:[self _nodeIterator]->previousNode(ec)];
    raiseOnDOMError(ec);
    return result;
}

- (void)detach
{
    ExceptionCode ec = 0;
    [self _nodeIterator]->detach(ec);
    raiseOnDOMError(ec);
}

@end

@implementation DOMNodeIterator(WebCoreInternal)

+ (DOMNodeIterator *)_nodeIteratorWith:(NodeIterator *)impl filter:(id <DOMNodeFilter>)filter
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithNodeIterator:impl filter:filter] autorelease];
}

@end

@implementation DOMTreeWalker

- (id)_initWithTreeWalker:(TreeWalker *)impl filter:(id <DOMNodeFilter>)filter
{
    ASSERT(impl);

    [super _init];
    _internal = DOM_cast<DOMObjectInternal *>(impl);
    impl->ref();
    addDOMWrapper(self, impl);
    m_filter = [filter retain];
    return self;
}

- (TreeWalker *)_treeWalker
{
    return DOM_cast<TreeWalker *>(_internal);
}

- (void)dealloc
{
    if (m_filter)
        [m_filter release];
    if (_internal) {
        DOM_cast<TreeWalker *>(_internal)->deref();
    }
    [super dealloc];
}

- (void)finalize
{
    if (_internal) {
        DOM_cast<TreeWalker *>(_internal)->deref();
    }
    [super finalize];
}

- (DOMNode *)root
{
    return [DOMNode _nodeWith:[self _treeWalker]->root()];
}

- (unsigned)whatToShow
{
    return [self _treeWalker]->whatToShow();
}

- (id <DOMNodeFilter>)filter
{
    if (m_filter)
        // This tree walker was created from the objc side
        return [[m_filter retain] autorelease];

    // This tree walker was created from the c++ side
    return [DOMNodeFilter _nodeFilterWith:[self _treeWalker]->filter()];
}

- (BOOL)expandEntityReferences
{
    return [self _treeWalker]->expandEntityReferences();
}

- (DOMNode *)currentNode
{
    return [DOMNode _nodeWith:[self _treeWalker]->currentNode()];
}

- (void)setCurrentNode:(DOMNode *)currentNode
{
    ExceptionCode ec = 0;
    [self _treeWalker]->setCurrentNode([currentNode _node], ec);
    raiseOnDOMError(ec);
}

- (DOMNode *)parentNode
{
    return [DOMNode _nodeWith:[self _treeWalker]->parentNode()];
}

- (DOMNode *)firstChild
{
    return [DOMNode _nodeWith:[self _treeWalker]->firstChild()];
}

- (DOMNode *)lastChild
{
    return [DOMNode _nodeWith:[self _treeWalker]->lastChild()];
}

- (DOMNode *)previousSibling
{
    return [DOMNode _nodeWith:[self _treeWalker]->previousSibling()];
}

- (DOMNode *)nextSibling
{
    return [DOMNode _nodeWith:[self _treeWalker]->nextSibling()];
}

- (DOMNode *)previousNode
{
    return [DOMNode _nodeWith:[self _treeWalker]->previousNode()];
}

- (DOMNode *)nextNode
{
    return [DOMNode _nodeWith:[self _treeWalker]->nextNode()];
}

@end

@implementation DOMTreeWalker (WebCoreInternal)

+ (DOMTreeWalker *)_treeWalkerWith:(TreeWalker *)impl filter:(id <DOMNodeFilter>)filter
{
    if (!impl)
        return nil;
    
    id cachedInstance;
    cachedInstance = getDOMWrapper(impl);
    if (cachedInstance)
        return [[cachedInstance retain] autorelease];
    
    return [[[self alloc] _initWithTreeWalker:impl filter:filter] autorelease];
}

@end

class ObjCNodeFilterCondition : public NodeFilterCondition 
{
public:
    ObjCNodeFilterCondition(id <DOMNodeFilter>);
    virtual ~ObjCNodeFilterCondition();
    virtual short acceptNode(Node*) const;

private:
    ObjCNodeFilterCondition(const ObjCNodeFilterCondition &);
    ObjCNodeFilterCondition &operator=(const ObjCNodeFilterCondition &);

    id <DOMNodeFilter> m_filter;
};

ObjCNodeFilterCondition::ObjCNodeFilterCondition(id <DOMNodeFilter> filter)
    : m_filter(filter)
{
    ASSERT(m_filter);
    CFRetain(m_filter);
}

ObjCNodeFilterCondition::~ObjCNodeFilterCondition()
{
    CFRelease(m_filter);
}

short ObjCNodeFilterCondition::acceptNode(Node* node) const
{
    if (!node)
        return NodeFilter::FILTER_REJECT;
    return [m_filter acceptNode:[DOMNode _nodeWith:node]];
}

@implementation DOMDocument (DOMDocumentTraversal)

- (DOMNodeIterator *)createNodeIterator:(DOMNode *)root :(unsigned)whatToShow :(id <DOMNodeFilter>)filter :(BOOL)expandEntityReferences
{
    RefPtr<NodeFilter> cppFilter;
    if (filter)
        cppFilter = new NodeFilter(new ObjCNodeFilterCondition(filter));
    ExceptionCode ec = 0;
    RefPtr<NodeIterator> impl = [self _document]->createNodeIterator([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
    raiseOnDOMError(ec);
    return [DOMNodeIterator _nodeIteratorWith:impl.get() filter:filter];
}

- (DOMTreeWalker *)createTreeWalker:(DOMNode *)root :(unsigned)whatToShow :(id <DOMNodeFilter>)filter :(BOOL)expandEntityReferences
{
    RefPtr<NodeFilter> cppFilter;
    if (filter)
        cppFilter = new NodeFilter(new ObjCNodeFilterCondition(filter));
    ExceptionCode ec = 0;
    RefPtr<TreeWalker> impl = [self _document]->createTreeWalker([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
    raiseOnDOMError(ec);
    return [DOMTreeWalker _treeWalkerWith:impl.get() filter:filter];
}

@end

ObjCEventListener* ObjCEventListener::find(id <DOMEventListener> listener)
{
    if (ListenerMap* map = listenerMap)
        return map->get(listener);
    return NULL;
}

ObjCEventListener *ObjCEventListener::create(id <DOMEventListener> listener)
{
    ObjCEventListener *wrapper = find(listener);
    if (!wrapper)
        wrapper = new ObjCEventListener(listener);
    wrapper->ref();
    return wrapper;
}

ObjCEventListener::ObjCEventListener(id <DOMEventListener> 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 _eventWith:event]];
}