1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#include "config.h"
23#include "HTMLMapElement.h"
24
25#include "Attribute.h"
26#include "Document.h"
27#include "HTMLAreaElement.h"
28#include "HTMLCollection.h"
29#include "HTMLImageElement.h"
30#include "HTMLNames.h"
31#include "HitTestResult.h"
32#include "IntSize.h"
33#include "NodeTraversal.h"
34#include "RenderObject.h"
35
36using namespace std;
37
38namespace WebCore {
39
40using namespace HTMLNames;
41
42HTMLMapElement::HTMLMapElement(const QualifiedName& tagName, Document* document)
43    : HTMLElement(tagName, document)
44{
45    ASSERT(hasTagName(mapTag));
46}
47
48PassRefPtr<HTMLMapElement> HTMLMapElement::create(Document* document)
49{
50    return adoptRef(new HTMLMapElement(mapTag, document));
51}
52
53PassRefPtr<HTMLMapElement> HTMLMapElement::create(const QualifiedName& tagName, Document* document)
54{
55    return adoptRef(new HTMLMapElement(tagName, document));
56}
57
58HTMLMapElement::~HTMLMapElement()
59{
60}
61
62bool HTMLMapElement::mapMouseEvent(LayoutPoint location, const LayoutSize& size, HitTestResult& result)
63{
64    HTMLAreaElement* defaultArea = 0;
65    Element* element = this;
66    while ((element = ElementTraversal::next(element, this))) {
67        if (element->hasTagName(areaTag)) {
68            HTMLAreaElement* areaElt = static_cast<HTMLAreaElement*>(element);
69            if (areaElt->isDefault()) {
70                if (!defaultArea)
71                    defaultArea = areaElt;
72            } else if (areaElt->mapMouseEvent(location, size, result))
73                return true;
74        }
75    }
76
77    if (defaultArea) {
78        result.setInnerNode(defaultArea);
79        result.setURLElement(defaultArea);
80    }
81    return defaultArea;
82}
83
84HTMLImageElement* HTMLMapElement::imageElement()
85{
86    RefPtr<HTMLCollection> images = document()->images();
87    for (unsigned i = 0; Node* curr = images->item(i); i++) {
88        if (!curr->hasTagName(imgTag))
89            continue;
90
91        // The HTMLImageElement's useMap() value includes the '#' symbol at the beginning,
92        // which has to be stripped off.
93        HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(curr);
94        String useMapName = imageElement->getAttribute(usemapAttr).string().substring(1);
95        if (equalIgnoringCase(useMapName, m_name))
96            return imageElement;
97    }
98
99    return 0;
100}
101
102void HTMLMapElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
103{
104    // FIXME: This logic seems wrong for XML documents.
105    // Either the id or name will be used depending on the order the attributes are parsed.
106
107    if (isIdAttributeName(name) || name == nameAttr) {
108        if (isIdAttributeName(name)) {
109            // Call base class so that hasID bit gets set.
110            HTMLElement::parseAttribute(name, value);
111            if (document()->isHTMLDocument())
112                return;
113        }
114        if (inDocument())
115            treeScope()->removeImageMap(this);
116        String mapName = value;
117        if (mapName[0] == '#')
118            mapName = mapName.substring(1);
119        m_name = document()->isHTMLDocument() ? mapName.lower() : mapName;
120        if (inDocument())
121            treeScope()->addImageMap(this);
122
123        return;
124    }
125
126    HTMLElement::parseAttribute(name, value);
127}
128
129PassRefPtr<HTMLCollection> HTMLMapElement::areas()
130{
131    return ensureCachedHTMLCollection(MapAreas);
132}
133
134Node::InsertionNotificationRequest HTMLMapElement::insertedInto(ContainerNode* insertionPoint)
135{
136    Node::InsertionNotificationRequest request = HTMLElement::insertedInto(insertionPoint);
137    if (insertionPoint->inDocument())
138        treeScope()->addImageMap(this);
139    return request;
140}
141
142void HTMLMapElement::removedFrom(ContainerNode* insertionPoint)
143{
144    if (insertionPoint->inDocument())
145        treeScope()->removeImageMap(this);
146    HTMLElement::removedFrom(insertionPoint);
147}
148
149}
150