| /* |
| * Copyright (C) 2011 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "ShadowRoot.h" |
| |
| #include "CSSStyleSelector.h" |
| #include "Document.h" |
| #include "DocumentFragment.h" |
| #include "Element.h" |
| #include "HTMLContentElement.h" |
| #include "HTMLContentSelector.h" |
| #include "HTMLNames.h" |
| #include "InsertionPoint.h" |
| #include "NodeRareData.h" |
| #include "ShadowTree.h" |
| #include "SVGNames.h" |
| #include "markup.h" |
| |
| #if ENABLE(SHADOW_DOM) |
| #include "RuntimeEnabledFeatures.h" |
| #endif |
| |
| namespace WebCore { |
| |
| ShadowRoot::ShadowRoot(Document* document) |
| : DocumentFragment(document, CreateShadowRoot) |
| , TreeScope(this) |
| , m_prev(0) |
| , m_next(0) |
| , m_applyAuthorSheets(false) |
| , m_insertionPointAssignedTo(0) |
| { |
| ASSERT(document); |
| |
| // Assume document as parent scope. |
| setParentTreeScope(document); |
| // Shadow tree scopes have the scope pointer point to themselves. |
| // This way, direct children will receive the correct scope pointer. |
| ensureRareData()->setTreeScope(this); |
| } |
| |
| ShadowRoot::~ShadowRoot() |
| { |
| ASSERT(!m_prev); |
| ASSERT(!m_next); |
| |
| // We must call clearRareData() here since a ShadowRoot class inherits TreeScope |
| // as well as Node. See a comment on TreeScope.h for the reason. |
| if (hasRareData()) |
| clearRareData(); |
| } |
| |
| static bool allowsAuthorShadowRoot(Element* element) |
| { |
| // FIXME: MEDIA recreates shadow root dynamically. |
| // https://bugs.webkit.org/show_bug.cgi?id=77936 |
| if (element->hasTagName(HTMLNames::videoTag) || element->hasTagName(HTMLNames::audioTag)) |
| return false; |
| |
| // FIXME: ValidationMessage recreates shadow root dynamically. |
| // https://bugs.webkit.org/show_bug.cgi?id=77937 |
| // Especially, INPUT recreates shadow root dynamically. |
| // https://bugs.webkit.org/show_bug.cgi?id=77930 |
| if (element->isFormControlElement()) |
| return false; |
| |
| // FIXME: We disable multiple shadow subtrees for SVG for while, because there will be problems to support it. |
| // https://bugs.webkit.org/show_bug.cgi?id=78205 |
| // Especially SVG TREF recreates shadow root dynamically. |
| // https://bugs.webkit.org/show_bug.cgi?id=77938 |
| if (element->isSVGElement()) |
| return false; |
| |
| return true; |
| } |
| |
| PassRefPtr<ShadowRoot> ShadowRoot::create(Element* element, ExceptionCode& ec) |
| { |
| return create(element, CreatingAuthorShadowRoot, ec); |
| } |
| |
| PassRefPtr<ShadowRoot> ShadowRoot::create(Element* element, ShadowRootCreationPurpose purpose, ExceptionCode& ec) |
| { |
| #if ENABLE(SHADOW_DOM) |
| bool isMultipleShadowSubtreesEnabled = RuntimeEnabledFeatures::multipleShadowSubtreesEnabled(); |
| #else |
| bool isMultipleShadowSubtreesEnabled = false; |
| #endif |
| |
| if (!element || (!isMultipleShadowSubtreesEnabled && element->hasShadowRoot())) { |
| ec = HIERARCHY_REQUEST_ERR; |
| return 0; |
| } |
| |
| // Since some elements recreates shadow root dynamically, multiple shadow subtrees won't work well in that element. |
| // Until they are fixed, we disable adding author shadow root for them. |
| if (purpose == CreatingAuthorShadowRoot && !allowsAuthorShadowRoot(element)) { |
| ec = HIERARCHY_REQUEST_ERR; |
| return 0; |
| } |
| |
| ASSERT(purpose != CreatingUserAgentShadowRoot || !element->hasShadowRoot()); |
| RefPtr<ShadowRoot> shadowRoot = adoptRef(new ShadowRoot(element->document())); |
| |
| ec = 0; |
| element->ensureShadowTree()->addShadowRoot(element, shadowRoot, ec); |
| if (ec) |
| return 0; |
| ASSERT(element == shadowRoot->host()); |
| ASSERT(element->hasShadowRoot()); |
| return shadowRoot.release(); |
| } |
| |
| String ShadowRoot::nodeName() const |
| { |
| return "#shadow-root"; |
| } |
| |
| PassRefPtr<Node> ShadowRoot::cloneNode(bool) |
| { |
| // ShadowRoot should not be arbitrarily cloned. |
| return 0; |
| } |
| |
| String ShadowRoot::innerHTML() const |
| { |
| return createMarkup(this, ChildrenOnly); |
| } |
| |
| void ShadowRoot::setInnerHTML(const String& markup, ExceptionCode& ec) |
| { |
| RefPtr<DocumentFragment> fragment = createFragmentFromSource(markup, host(), ec); |
| if (fragment) |
| replaceChildrenWithFragment(this, fragment.release(), ec); |
| } |
| |
| bool ShadowRoot::childTypeAllowed(NodeType type) const |
| { |
| switch (type) { |
| case ELEMENT_NODE: |
| case PROCESSING_INSTRUCTION_NODE: |
| case COMMENT_NODE: |
| case TEXT_NODE: |
| case CDATA_SECTION_NODE: |
| case ENTITY_REFERENCE_NODE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| ShadowTree* ShadowRoot::tree() const |
| { |
| if (host()) |
| return host()->shadowTree(); |
| return 0; |
| } |
| |
| bool ShadowRoot::hasInsertionPoint() const |
| { |
| for (Node* n = firstChild(); n; n = n->traverseNextNode(this)) { |
| if (isInsertionPoint(n)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool ShadowRoot::applyAuthorSheets() const |
| { |
| return m_applyAuthorSheets; |
| } |
| |
| void ShadowRoot::setApplyAuthorSheets(bool value) |
| { |
| m_applyAuthorSheets = value; |
| } |
| |
| void ShadowRoot::attach() |
| { |
| CSSStyleSelector* styleSelector = document()->styleSelector(); |
| styleSelector->pushParentShadowRoot(this); |
| DocumentFragment::attach(); |
| styleSelector->popParentShadowRoot(this); |
| } |
| |
| } |