1/* 2 * Copyright (C) 2011 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 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "ContentDistributor.h" 29 30#include "ElementShadow.h" 31#include "HTMLContentElement.h" 32#include "NodeTraversal.h" 33#include "ShadowRoot.h" 34 35 36namespace WebCore { 37 38ContentDistributor::ContentDistributor() 39 : m_insertionPointListIsValid(true) 40 , m_validity(Undetermined) 41{ 42} 43 44ContentDistributor::~ContentDistributor() 45{ 46} 47 48void ContentDistributor::invalidateInsertionPointList() 49{ 50 m_insertionPointListIsValid = false; 51 m_insertionPointList.clear(); 52} 53 54const Vector<RefPtr<InsertionPoint> >& ContentDistributor::ensureInsertionPointList(ShadowRoot* shadowRoot) 55{ 56 if (m_insertionPointListIsValid) 57 return m_insertionPointList; 58 59 m_insertionPointListIsValid = true; 60 ASSERT(m_insertionPointList.isEmpty()); 61 62 for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) { 63 if (element->isInsertionPoint()) 64 m_insertionPointList.append(toInsertionPoint(element)); 65 } 66 67 return m_insertionPointList; 68} 69 70InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const 71{ 72 return m_nodeToInsertionPoint.get(key); 73} 74 75void ContentDistributor::distribute(Element* host) 76{ 77 ASSERT(needsDistribution()); 78 ASSERT(m_nodeToInsertionPoint.isEmpty()); 79 ASSERT(!host->containingShadowRoot() || host->containingShadowRoot()->owner()->distributor().isValid()); 80 81 m_validity = Valid; 82 83 if (ShadowRoot* root = host->shadowRoot()) { 84 const Vector<RefPtr<InsertionPoint> >& insertionPoints = ensureInsertionPointList(root); 85 for (size_t i = 0; i < insertionPoints.size(); ++i) { 86 InsertionPoint* point = insertionPoints[i].get(); 87 if (!point->isActive()) 88 continue; 89 90 distributeSelectionsTo(point, host); 91 } 92 } 93} 94 95bool ContentDistributor::invalidate(Element* host) 96{ 97 ASSERT(needsInvalidation()); 98 bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty(); 99 100 if (ShadowRoot* root = host->shadowRoot()) { 101 const Vector<RefPtr<InsertionPoint> >& insertionPoints = ensureInsertionPointList(root); 102 for (size_t i = 0; i < insertionPoints.size(); ++i) { 103 needsReattach = true; 104 insertionPoints[i]->clearDistribution(); 105 } 106 } 107 108 m_validity = Invalidating; 109 m_nodeToInsertionPoint.clear(); 110 return needsReattach; 111} 112 113void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, Element* host) 114{ 115 for (Node* child = host->firstChild(); child; child = child->nextSibling()) { 116 ASSERT(!child->isInsertionPoint()); 117 118 if (insertionPoint->matchTypeFor(child) != InsertionPoint::AlwaysMatches) 119 continue; 120 121 m_nodeToInsertionPoint.add(child, insertionPoint); 122 } 123 124 if (m_nodeToInsertionPoint.isEmpty()) 125 return; 126 insertionPoint->setHasDistribution(); 127} 128 129void ContentDistributor::ensureDistribution(ShadowRoot* shadowRoot) 130{ 131 ASSERT(shadowRoot); 132 133 Vector<ElementShadow*, 8> elementShadows; 134 for (Element* current = shadowRoot->host(); current; current = current->shadowHost()) { 135 ElementShadow* elementShadow = current->shadow(); 136 if (!elementShadow->distributor().needsDistribution()) 137 break; 138 139 elementShadows.append(elementShadow); 140 } 141 142 for (size_t i = elementShadows.size(); i > 0; --i) 143 elementShadows[i - 1]->distributor().distribute(elementShadows[i - 1]->host()); 144} 145 146 147void ContentDistributor::invalidateDistribution(Element* host) 148{ 149 bool didNeedInvalidation = needsInvalidation(); 150 bool needsReattach = didNeedInvalidation ? invalidate(host) : false; 151 152 if (needsReattach && host->attached()) { 153 for (Node* n = host->firstChild(); n; n = n->nextSibling()) 154 n->lazyReattach(); 155 host->setNeedsStyleRecalc(); 156 } 157 158 if (didNeedInvalidation) { 159 ASSERT(m_validity == Invalidating); 160 m_validity = Invalidated; 161 } 162} 163 164void ContentDistributor::didShadowBoundaryChange(Element* host) 165{ 166 setValidity(Undetermined); 167 invalidateDistribution(host); 168} 169 170} 171