• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Peter Kelly (pmk@post.com)
5  *           (C) 2001 Dirk Mueller (mueller@kde.org)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 #include "config.h"
24 #include "Attr.h"
25 
26 #include "Element.h"
27 #include "ExceptionCode.h"
28 #include "HTMLNames.h"
29 #include "ScopedEventQueue.h"
30 #include "Text.h"
31 #include "XMLNSNames.h"
32 
33 namespace WebCore {
34 
35 using namespace HTMLNames;
36 
Attr(Element * element,Document * document,PassRefPtr<Attribute> attribute)37 inline Attr::Attr(Element* element, Document* document, PassRefPtr<Attribute> attribute)
38     : ContainerNode(document)
39     , m_element(element)
40     , m_attribute(attribute)
41     , m_ignoreChildrenChanged(0)
42     , m_specified(true)
43 {
44     ASSERT(!m_attribute->attr());
45     m_attribute->bindAttr(this);
46 }
47 
create(Element * element,Document * document,PassRefPtr<Attribute> attribute)48 PassRefPtr<Attr> Attr::create(Element* element, Document* document, PassRefPtr<Attribute> attribute)
49 {
50     RefPtr<Attr> attr = adoptRef(new Attr(element, document, attribute));
51     attr->createTextChild();
52     return attr.release();
53 }
54 
~Attr()55 Attr::~Attr()
56 {
57     ASSERT(m_attribute->attr() == this);
58     m_attribute->unbindAttr(this);
59 }
60 
createTextChild()61 void Attr::createTextChild()
62 {
63     ASSERT(refCount());
64     if (!m_attribute->value().isEmpty()) {
65         RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string());
66 
67         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
68         // but much more efficiently.
69         textNode->setParent(this);
70         setFirstChild(textNode.get());
71         setLastChild(textNode.get());
72     }
73 }
74 
nodeName() const75 String Attr::nodeName() const
76 {
77     return name();
78 }
79 
nodeType() const80 Node::NodeType Attr::nodeType() const
81 {
82     return ATTRIBUTE_NODE;
83 }
84 
localName() const85 const AtomicString& Attr::localName() const
86 {
87     return m_attribute->localName();
88 }
89 
namespaceURI() const90 const AtomicString& Attr::namespaceURI() const
91 {
92     return m_attribute->namespaceURI();
93 }
94 
prefix() const95 const AtomicString& Attr::prefix() const
96 {
97     return m_attribute->prefix();
98 }
99 
setPrefix(const AtomicString & prefix,ExceptionCode & ec)100 void Attr::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
101 {
102     ec = 0;
103     checkSetPrefix(prefix, ec);
104     if (ec)
105         return;
106 
107     if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI)
108         || static_cast<Attr*>(this)->qualifiedName() == xmlnsAtom) {
109         ec = NAMESPACE_ERR;
110         return;
111     }
112 
113     m_attribute->setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
114 }
115 
nodeValue() const116 String Attr::nodeValue() const
117 {
118     return value();
119 }
120 
setValue(const AtomicString & value)121 void Attr::setValue(const AtomicString& value)
122 {
123     EventQueueScope scope;
124     m_ignoreChildrenChanged++;
125     removeChildren();
126     m_attribute->setValue(value);
127     createTextChild();
128     m_ignoreChildrenChanged--;
129 }
130 
setValue(const AtomicString & value,ExceptionCode &)131 void Attr::setValue(const AtomicString& value, ExceptionCode&)
132 {
133     if (m_element && m_element->isIdAttributeName(m_attribute->name()))
134         m_element->updateId(m_element->getIdAttribute(), value);
135 
136     setValue(value);
137 
138     if (m_element)
139         m_element->attributeChanged(m_attribute.get());
140 }
141 
setNodeValue(const String & v,ExceptionCode & ec)142 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
143 {
144     setValue(v, ec);
145 }
146 
cloneNode(bool)147 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
148 {
149     RefPtr<Attr> clone = adoptRef(new Attr(0, document(), m_attribute->clone()));
150     cloneChildNodes(clone.get());
151     return clone.release();
152 }
153 
154 // DOM Section 1.1.1
childTypeAllowed(NodeType type) const155 bool Attr::childTypeAllowed(NodeType type) const
156 {
157     switch (type) {
158         case TEXT_NODE:
159         case ENTITY_REFERENCE_NODE:
160             return true;
161         default:
162             return false;
163     }
164 }
165 
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)166 void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
167 {
168     if (m_ignoreChildrenChanged > 0)
169         return;
170 
171     Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
172 
173     // FIXME: We should include entity references in the value
174 
175     String val = "";
176     for (Node *n = firstChild(); n; n = n->nextSibling()) {
177         if (n->isTextNode())
178             val += static_cast<Text *>(n)->data();
179     }
180 
181     if (m_element && m_element->isIdAttributeName(m_attribute->name()))
182         m_element->updateId(m_attribute->value(), val);
183 
184     m_attribute->setValue(val.impl());
185     if (m_element)
186         m_element->attributeChanged(m_attribute.get());
187 }
188 
isId() const189 bool Attr::isId() const
190 {
191     return qualifiedName().matches(document()->idAttributeName());
192 }
193 
194 }
195