Home | History | Annotate | Download | only in custom
      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/CustomElementRegistrationContext.h"
     33 
     34 #include "bindings/v8/ExceptionState.h"
     35 #include "core/HTMLNames.h"
     36 #include "core/SVGNames.h"
     37 #include "core/dom/Document.h"
     38 #include "core/dom/Element.h"
     39 #include "core/dom/custom/CustomElement.h"
     40 #include "core/dom/custom/CustomElementDefinition.h"
     41 #include "core/dom/custom/CustomElementScheduler.h"
     42 #include "core/html/HTMLElement.h"
     43 #include "core/html/HTMLUnknownElement.h"
     44 #include "core/svg/SVGUnknownElement.h"
     45 #include "wtf/RefPtr.h"
     46 
     47 namespace WebCore {
     48 
     49 CustomElementRegistrationContext::CustomElementRegistrationContext()
     50     : m_candidates(CustomElementUpgradeCandidateMap::create())
     51 {
     52 }
     53 
     54 void CustomElementRegistrationContext::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& type, CustomElement::NameSet validNames, ExceptionState& exceptionState)
     55 {
     56     CustomElementDefinition* definition = m_registry.registerElement(document, constructorBuilder, type, validNames, exceptionState);
     57 
     58     if (!definition)
     59         return;
     60 
     61     // Upgrade elements that were waiting for this definition.
     62     OwnPtrWillBeRawPtr<CustomElementUpgradeCandidateMap::ElementSet> upgradeCandidates = m_candidates->takeUpgradeCandidatesFor(definition->descriptor());
     63 
     64     if (!upgradeCandidates)
     65         return;
     66 
     67     for (CustomElementUpgradeCandidateMap::ElementSet::const_iterator it = upgradeCandidates->begin(); it != upgradeCandidates->end(); ++it)
     68         CustomElement::define(*it, definition);
     69 }
     70 
     71 PassRefPtrWillBeRawPtr<Element> CustomElementRegistrationContext::createCustomTagElement(Document& document, const QualifiedName& tagName)
     72 {
     73     ASSERT(CustomElement::isValidName(tagName.localName()));
     74 
     75     RefPtrWillBeRawPtr<Element> element;
     76 
     77     if (HTMLNames::xhtmlNamespaceURI == tagName.namespaceURI()) {
     78         element = HTMLElement::create(tagName, document);
     79     } else if (SVGNames::svgNamespaceURI == tagName.namespaceURI()) {
     80         element = SVGUnknownElement::create(tagName, document);
     81     } else {
     82         // XML elements are not custom elements, so return early.
     83         return Element::create(tagName, &document);
     84     }
     85 
     86     element->setCustomElementState(Element::WaitingForUpgrade);
     87     resolveOrScheduleResolution(element.get(), nullAtom);
     88     return element.release();
     89 }
     90 
     91 void CustomElementRegistrationContext::didGiveTypeExtension(Element* element, const AtomicString& type)
     92 {
     93     resolveOrScheduleResolution(element, type);
     94 }
     95 
     96 void CustomElementRegistrationContext::resolveOrScheduleResolution(Element* element, const AtomicString& typeExtension)
     97 {
     98     // If an element has a custom tag name it takes precedence over
     99     // the "is" attribute (if any).
    100     const AtomicString& type = CustomElement::isValidName(element->localName())
    101         ? element->localName()
    102         : typeExtension;
    103     ASSERT(!type.isNull());
    104 
    105     CustomElementDescriptor descriptor(type, element->namespaceURI(), element->localName());
    106     ASSERT(element->customElementState() == Element::WaitingForUpgrade);
    107 
    108     CustomElementScheduler::resolveOrScheduleResolution(this, element, descriptor);
    109 }
    110 
    111 void CustomElementRegistrationContext::resolve(Element* element, const CustomElementDescriptor& descriptor)
    112 {
    113     CustomElementDefinition* definition = m_registry.find(descriptor);
    114     if (definition) {
    115         CustomElement::define(element, definition);
    116     } else {
    117         ASSERT(element->customElementState() == Element::WaitingForUpgrade);
    118         m_candidates->add(descriptor, element);
    119     }
    120 }
    121 
    122 void CustomElementRegistrationContext::setIsAttributeAndTypeExtension(Element* element, const AtomicString& type)
    123 {
    124     ASSERT(element);
    125     ASSERT(!type.isEmpty());
    126     element->setAttribute(HTMLNames::isAttr, type);
    127     setTypeExtension(element, type);
    128 }
    129 
    130 void CustomElementRegistrationContext::setTypeExtension(Element* element, const AtomicString& type)
    131 {
    132     if (!element->isHTMLElement() && !element->isSVGElement())
    133         return;
    134 
    135     CustomElementRegistrationContext* context = element->document().registrationContext();
    136     if (!context)
    137         return;
    138 
    139     if (element->isCustomElement()) {
    140         // This can happen if:
    141         // 1. The element has a custom tag, which takes precedence over
    142         //    type extensions.
    143         // 2. Undoing a command (eg ReplaceNodeWithSpan) recycles an
    144         //    element but tries to overwrite its attribute list.
    145         return;
    146     }
    147 
    148     // Custom tags take precedence over type extensions
    149     ASSERT(!CustomElement::isValidName(element->localName()));
    150 
    151     if (!CustomElement::isValidName(type))
    152         return;
    153 
    154     element->setCustomElementState(Element::WaitingForUpgrade);
    155     context->didGiveTypeExtension(element, type);
    156 }
    157 
    158 void CustomElementRegistrationContext::trace(Visitor* visitor)
    159 {
    160     visitor->trace(m_candidates);
    161 }
    162 
    163 } // namespace WebCore
    164