1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of Google Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "core/dom/custom/CustomElement.h"
33
34 #include "HTMLNames.h"
35 #include "MathMLNames.h"
36 #include "RuntimeEnabledFeatures.h"
37 #include "SVGNames.h"
38 #include "core/dom/Element.h"
39 #include "core/dom/custom/CustomElementCallbackScheduler.h"
40 #include "core/dom/custom/CustomElementObserver.h"
41
42 namespace WebCore {
43
embedderCustomElementNames()44 Vector<AtomicString>& CustomElement::embedderCustomElementNames()
45 {
46 DEFINE_STATIC_LOCAL(Vector<AtomicString>, names, ());
47 return names;
48 }
49
addEmbedderCustomElementName(const AtomicString & name)50 void CustomElement::addEmbedderCustomElementName(const AtomicString& name)
51 {
52 AtomicString lower = name.lower();
53 if (isValidName(lower, EmbedderNames))
54 return;
55 embedderCustomElementNames().append(lower);
56 }
57
enabledNameSet()58 static CustomElement::NameSet enabledNameSet()
59 {
60 return CustomElement::NameSet((RuntimeEnabledFeatures::customElementsEnabled() ? CustomElement::StandardNames : 0) | (RuntimeEnabledFeatures::embedderCustomElementsEnabled() ? CustomElement::EmbedderNames : 0));
61 }
62
isValidName(const AtomicString & name,NameSet validNames)63 bool CustomElement::isValidName(const AtomicString& name, NameSet validNames)
64 {
65 validNames = NameSet(validNames & enabledNameSet());
66
67 if ((validNames & EmbedderNames) && kNotFound != embedderCustomElementNames().find(name))
68 return Document::isValidName(name);
69
70 if ((validNames & StandardNames) && kNotFound != name.find('-')) {
71 DEFINE_STATIC_LOCAL(Vector<AtomicString>, reservedNames, ());
72 if (reservedNames.isEmpty()) {
73 reservedNames.append(MathMLNames::annotation_xmlTag.localName());
74 // In principle, "color-profile" should exist in the SVGNames
75 // namespace, but we don't implement the color-profile element.
76 reservedNames.append("color-profile");
77 reservedNames.append(SVGNames::font_faceTag.localName());
78 reservedNames.append(SVGNames::font_face_srcTag.localName());
79 reservedNames.append(SVGNames::font_face_uriTag.localName());
80 reservedNames.append(SVGNames::font_face_formatTag.localName());
81 reservedNames.append(SVGNames::font_face_nameTag.localName());
82 reservedNames.append(SVGNames::missing_glyphTag.localName());
83 }
84
85 if (kNotFound == reservedNames.find(name))
86 return Document::isValidName(name.string());
87 }
88
89 return false;
90 }
91
define(Element * element,PassRefPtr<CustomElementDefinition> passDefinition)92 void CustomElement::define(Element* element, PassRefPtr<CustomElementDefinition> passDefinition)
93 {
94 RefPtr<CustomElementDefinition> definition(passDefinition);
95
96 switch (element->customElementState()) {
97 case Element::NotCustomElement:
98 case Element::Upgraded:
99 ASSERT_NOT_REACHED();
100 break;
101
102 case Element::WaitingForUpgrade:
103 definitions().add(element, definition);
104 CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
105 break;
106 }
107 }
108
definitionFor(Element * element)109 CustomElementDefinition* CustomElement::definitionFor(Element* element)
110 {
111 CustomElementDefinition* definition = definitions().get(element);
112 ASSERT(definition);
113 return definition;
114 }
115
attributeDidChange(Element * element,const AtomicString & name,const AtomicString & oldValue,const AtomicString & newValue)116 void CustomElement::attributeDidChange(Element* element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue)
117 {
118 ASSERT(element->customElementState() == Element::Upgraded);
119 CustomElementCallbackScheduler::scheduleAttributeChangedCallback(definitionFor(element)->callbacks(), element, name, oldValue, newValue);
120 }
121
didEnterDocument(Element * element,const Document & document)122 void CustomElement::didEnterDocument(Element* element, const Document& document)
123 {
124 ASSERT(element->customElementState() == Element::Upgraded);
125 if (!document.domWindow())
126 return;
127 CustomElementCallbackScheduler::scheduleAttachedCallback(definitionFor(element)->callbacks(), element);
128 }
129
didLeaveDocument(Element * element,const Document & document)130 void CustomElement::didLeaveDocument(Element* element, const Document& document)
131 {
132 ASSERT(element->customElementState() == Element::Upgraded);
133 if (!document.domWindow())
134 return;
135 CustomElementCallbackScheduler::scheduleDetachedCallback(definitionFor(element)->callbacks(), element);
136 }
137
wasDestroyed(Element * element)138 void CustomElement::wasDestroyed(Element* element)
139 {
140 switch (element->customElementState()) {
141 case Element::NotCustomElement:
142 ASSERT_NOT_REACHED();
143 break;
144
145 case Element::WaitingForUpgrade:
146 case Element::Upgraded:
147 definitions().remove(element);
148 CustomElementObserver::notifyElementWasDestroyed(element);
149 break;
150 }
151 }
152
add(Element * element,PassRefPtr<CustomElementDefinition> definition)153 void CustomElement::DefinitionMap::add(Element* element, PassRefPtr<CustomElementDefinition> definition)
154 {
155 ASSERT(definition.get());
156 DefinitionMap::ElementDefinitionHashMap::AddResult result = m_definitions.add(element, definition);
157 ASSERT_UNUSED(result, result.isNewEntry);
158 }
159
definitions()160 CustomElement::DefinitionMap& CustomElement::definitions()
161 {
162 DEFINE_STATIC_LOCAL(DefinitionMap, map, ());
163 return map;
164 }
165
166 } // namespace WebCore
167