• 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 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 "Document.h"
27 #include "Element.h"
28 #include "ExceptionCode.h"
29 #include "Text.h"
30 #include "XMLNSNames.h"
31 
32 namespace WebCore {
33 
34 using namespace HTMLNames;
35 
Attr(Element * element,Document * document,PassRefPtr<Attribute> attribute)36 inline Attr::Attr(Element* element, Document* document, PassRefPtr<Attribute> attribute)
37     : ContainerNode(document)
38     , m_element(element)
39     , m_attribute(attribute)
40     , m_ignoreChildrenChanged(0)
41     , m_specified(true)
42 {
43     ASSERT(!m_attribute->attr());
44     m_attribute->m_impl = this;
45 }
46 
create(Element * element,Document * document,PassRefPtr<Attribute> attribute)47 PassRefPtr<Attr> Attr::create(Element* element, Document* document, PassRefPtr<Attribute> attribute)
48 {
49     RefPtr<Attr> attr = adoptRef(new Attr(element, document, attribute));
50     attr->createTextChild();
51     return attr.release();
52 }
53 
~Attr()54 Attr::~Attr()
55 {
56     ASSERT(m_attribute->attr() == this);
57     m_attribute->m_impl = 0;
58 }
59 
createTextChild()60 void Attr::createTextChild()
61 {
62     ASSERT(refCount());
63     if (!m_attribute->value().isEmpty()) {
64         RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string());
65 
66         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
67         // but much more efficiently.
68         textNode->setParent(this);
69         setFirstChild(textNode.get());
70         setLastChild(textNode.get());
71     }
72 }
73 
nodeName() const74 String Attr::nodeName() const
75 {
76     return name();
77 }
78 
nodeType() const79 Node::NodeType Attr::nodeType() const
80 {
81     return ATTRIBUTE_NODE;
82 }
83 
localName() const84 const AtomicString& Attr::localName() const
85 {
86     return m_attribute->localName();
87 }
88 
namespaceURI() const89 const AtomicString& Attr::namespaceURI() const
90 {
91     return m_attribute->namespaceURI();
92 }
93 
prefix() const94 const AtomicString& Attr::prefix() const
95 {
96     return m_attribute->prefix();
97 }
98 
setPrefix(const AtomicString & prefix,ExceptionCode & ec)99 void Attr::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
100 {
101     ec = 0;
102     checkSetPrefix(prefix, ec);
103     if (ec)
104         return;
105 
106     if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI)
107         || static_cast<Attr*>(this)->qualifiedName() == xmlnsAtom) {
108         ec = NAMESPACE_ERR;
109         return;
110     }
111 
112     m_attribute->setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
113 }
114 
nodeValue() const115 String Attr::nodeValue() const
116 {
117     return value();
118 }
119 
setValue(const AtomicString & value)120 void Attr::setValue(const AtomicString& value)
121 {
122     m_ignoreChildrenChanged++;
123     removeChildren();
124     m_attribute->setValue(value);
125     createTextChild();
126     m_ignoreChildrenChanged--;
127 }
128 
setValue(const AtomicString & value,ExceptionCode &)129 void Attr::setValue(const AtomicString& value, ExceptionCode&)
130 {
131     if (m_element && m_attribute->name() == m_element->idAttributeName())
132         m_element->updateId(m_element->getIDAttribute(), value);
133 
134     setValue(value);
135 
136     if (m_element)
137         m_element->attributeChanged(m_attribute.get());
138 }
139 
setNodeValue(const String & v,ExceptionCode & ec)140 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
141 {
142     setValue(v, ec);
143 }
144 
cloneNode(bool)145 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
146 {
147     RefPtr<Attr> clone = adoptRef(new Attr(0, document(), m_attribute->clone()));
148     cloneChildNodes(clone.get());
149     return clone.release();
150 }
151 
152 // DOM Section 1.1.1
childTypeAllowed(NodeType type)153 bool Attr::childTypeAllowed(NodeType type)
154 {
155     switch (type) {
156         case TEXT_NODE:
157         case ENTITY_REFERENCE_NODE:
158             return true;
159         default:
160             return false;
161     }
162 }
163 
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)164 void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
165 {
166     if (m_ignoreChildrenChanged > 0)
167         return;
168 
169     Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
170 
171     // FIXME: We should include entity references in the value
172 
173     String val = "";
174     for (Node *n = firstChild(); n; n = n->nextSibling()) {
175         if (n->isTextNode())
176             val += static_cast<Text *>(n)->data();
177     }
178 
179     if (m_element && m_attribute->name() == m_element->idAttributeName())
180         m_element->updateId(m_attribute->value(), val);
181 
182     m_attribute->setValue(val.impl());
183     if (m_element)
184         m_element->attributeChanged(m_attribute.get());
185 }
186 
isId() const187 bool Attr::isId() const
188 {
189     return qualifiedName().matches(m_element ? m_element->idAttributeName() : idAttr);
190 }
191 
192 }
193