Home | History | Annotate | Download | only in shadow
      1 /*
      2  * Copyright (C) 2012 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this 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/shadow/InsertionPoint.h"
     33 
     34 #include "HTMLNames.h"
     35 #include "core/dom/QualifiedName.h"
     36 #include "core/dom/StaticNodeList.h"
     37 #include "core/dom/shadow/ElementShadow.h"
     38 #include "core/dom/shadow/ShadowRoot.h"
     39 
     40 namespace WebCore {
     41 
     42 using namespace HTMLNames;
     43 
     44 InsertionPoint::InsertionPoint(const QualifiedName& tagName, Document* document)
     45     : HTMLElement(tagName, document, CreateInsertionPoint)
     46     , m_registeredWithShadowRoot(false)
     47 {
     48     setHasCustomStyleCallbacks();
     49 }
     50 
     51 InsertionPoint::~InsertionPoint()
     52 {
     53 }
     54 
     55 void InsertionPoint::attach(const AttachContext& context)
     56 {
     57     // FIXME: This loop shouldn't be needed since the distributed nodes should
     58     // never be detached, we can probably remove it.
     59     for (size_t i = 0; i < m_distribution.size(); ++i) {
     60         if (!m_distribution.at(i)->attached())
     61             m_distribution.at(i)->attach(context);
     62     }
     63 
     64     HTMLElement::attach(context);
     65 }
     66 
     67 void InsertionPoint::detach(const AttachContext& context)
     68 {
     69     for (size_t i = 0; i < m_distribution.size(); ++i)
     70         m_distribution.at(i)->lazyReattachIfAttached();
     71 
     72     HTMLElement::detach(context);
     73 }
     74 
     75 void InsertionPoint::willRecalcStyle(StyleChange change)
     76 {
     77     if (change < Inherit)
     78         return;
     79     for (size_t i = 0; i < m_distribution.size(); ++i)
     80         m_distribution.at(i)->setNeedsStyleRecalc(LocalStyleChange);
     81 }
     82 
     83 bool InsertionPoint::shouldUseFallbackElements() const
     84 {
     85     return isActive() && !hasDistribution();
     86 }
     87 
     88 bool InsertionPoint::isActive() const
     89 {
     90     if (!containingShadowRoot())
     91         return false;
     92     const Node* node = parentNode();
     93     while (node) {
     94         if (node->isInsertionPoint())
     95             return false;
     96 
     97         node = node->parentNode();
     98     }
     99     return true;
    100 }
    101 
    102 PassRefPtr<NodeList> InsertionPoint::getDistributedNodes()
    103 {
    104     document()->updateDistributionForNodeIfNeeded(this);
    105 
    106     Vector<RefPtr<Node> > nodes;
    107     for (size_t i = 0; i < m_distribution.size(); ++i)
    108         nodes.append(m_distribution.at(i));
    109 
    110     return StaticNodeList::adopt(nodes);
    111 }
    112 
    113 bool InsertionPoint::rendererIsNeeded(const NodeRenderingContext& context)
    114 {
    115     return !isActive() && HTMLElement::rendererIsNeeded(context);
    116 }
    117 
    118 void InsertionPoint::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    119 {
    120     HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    121     if (ShadowRoot* root = containingShadowRoot()) {
    122         if (ElementShadow* rootOwner = root->owner())
    123             rootOwner->setNeedsDistributionRecalc();
    124     }
    125 }
    126 
    127 Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint)
    128 {
    129     HTMLElement::insertedInto(insertionPoint);
    130 
    131     if (ShadowRoot* root = containingShadowRoot()) {
    132         if (ElementShadow* rootOwner = root->owner()) {
    133             rootOwner->setNeedsDistributionRecalc();
    134             if (isActive() && !m_registeredWithShadowRoot && insertionPoint->treeScope()->rootNode() == root) {
    135                 m_registeredWithShadowRoot = true;
    136                 root->ensureScopeDistribution()->registerInsertionPoint(this);
    137                 rootOwner->didAffectApplyAuthorStyles();
    138                 if (canAffectSelector())
    139                     rootOwner->willAffectSelector();
    140             }
    141         }
    142     }
    143 
    144     return InsertionDone;
    145 }
    146 
    147 void InsertionPoint::removedFrom(ContainerNode* insertionPoint)
    148 {
    149     ShadowRoot* root = containingShadowRoot();
    150     if (!root)
    151         root = insertionPoint->containingShadowRoot();
    152 
    153     if (root) {
    154         if (ElementShadow* rootOwner = root->owner())
    155             rootOwner->setNeedsDistributionRecalc();
    156     }
    157 
    158     // host can be null when removedFrom() is called from ElementShadow destructor.
    159     ElementShadow* rootOwner = root ? root->owner() : 0;
    160 
    161     // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
    162     clearDistribution();
    163 
    164     if (m_registeredWithShadowRoot && insertionPoint->treeScope()->rootNode() == root) {
    165         ASSERT(root);
    166         m_registeredWithShadowRoot = false;
    167         root->ensureScopeDistribution()->unregisterInsertionPoint(this);
    168         if (rootOwner) {
    169             rootOwner->didAffectApplyAuthorStyles();
    170             if (canAffectSelector())
    171                 rootOwner->willAffectSelector();
    172         }
    173     }
    174 
    175     HTMLElement::removedFrom(insertionPoint);
    176 }
    177 
    178 void InsertionPoint::parseAttribute(const QualifiedName& name, const AtomicString& value)
    179 {
    180     if (name == reset_style_inheritanceAttr) {
    181         if (!inDocument() || !attached() || !isActive())
    182             return;
    183         containingShadowRoot()->host()->setNeedsStyleRecalc();
    184     } else
    185         HTMLElement::parseAttribute(name, value);
    186 }
    187 
    188 bool InsertionPoint::resetStyleInheritance() const
    189 {
    190     return fastHasAttribute(reset_style_inheritanceAttr);
    191 }
    192 
    193 void InsertionPoint::setResetStyleInheritance(bool value)
    194 {
    195     setBooleanAttribute(reset_style_inheritanceAttr, value);
    196 }
    197 
    198 InsertionPoint* resolveReprojection(const Node* projectedNode)
    199 {
    200     InsertionPoint* insertionPoint = 0;
    201     const Node* current = projectedNode;
    202 
    203     while (current) {
    204         if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
    205             if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(projectedNode)) {
    206                 current = insertedTo;
    207                 insertionPoint = insertedTo;
    208                 continue;
    209             }
    210         }
    211 
    212         if (Node* parent = parentNodeForDistribution(current)) {
    213             if (InsertionPoint* insertedTo = parent->isShadowRoot() ? toShadowRoot(parent)->insertionPoint() : 0) {
    214                 current = insertedTo;
    215                 insertionPoint = insertedTo;
    216                 continue;
    217             }
    218         }
    219 
    220         break;
    221     }
    222 
    223     return insertionPoint;
    224 }
    225 
    226 void collectInsertionPointsWhereNodeIsDistributed(const Node* node, Vector<InsertionPoint*, 8>& results)
    227 {
    228     const Node* current = node;
    229     while (true) {
    230         if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
    231             if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(node)) {
    232                 current = insertedTo;
    233                 results.append(insertedTo);
    234                 continue;
    235             }
    236         }
    237         if (Node* parent = parentNodeForDistribution(current)) {
    238             if (InsertionPoint* insertedTo = parent->isShadowRoot() ? toShadowRoot(parent)->insertionPoint() : 0) {
    239                 current = insertedTo;
    240                 results.append(insertedTo);
    241                 continue;
    242             }
    243         }
    244         return;
    245     }
    246 }
    247 
    248 } // namespace WebCore
    249