1 /* 2 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 #include "config.h" 21 22 #if ENABLE(SVG) 23 #include "RenderSVGResourceContainer.h" 24 25 #include "RenderSVGShadowTreeRootContainer.h" 26 #include "SVGStyledTransformableElement.h" 27 28 namespace WebCore { 29 30 static inline SVGDocumentExtensions* svgExtensionsFromNode(Node* node) 31 { 32 ASSERT(node); 33 ASSERT(node->document()); 34 return node->document()->accessSVGExtensions(); 35 } 36 37 RenderSVGResourceContainer::RenderSVGResourceContainer(SVGStyledElement* node) 38 : RenderSVGHiddenContainer(node) 39 , m_id(node->hasID() ? node->getIdAttribute() : nullAtom) 40 , m_registered(false) 41 { 42 } 43 44 RenderSVGResourceContainer::~RenderSVGResourceContainer() 45 { 46 if (m_registered) 47 svgExtensionsFromNode(node())->removeResource(m_id); 48 } 49 50 void RenderSVGResourceContainer::layout() 51 { 52 // Invalidate all resources if our layout changed. 53 if (m_everHadLayout && selfNeedsLayout()) 54 removeAllClientsFromCache(); 55 56 RenderSVGHiddenContainer::layout(); 57 } 58 59 void RenderSVGResourceContainer::destroy() 60 { 61 SVGResourcesCache::resourceDestroyed(this); 62 RenderSVGHiddenContainer::destroy(); 63 } 64 65 void RenderSVGResourceContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 66 { 67 RenderSVGHiddenContainer::styleDidChange(diff, oldStyle); 68 69 if (!m_registered) { 70 m_registered = true; 71 registerResource(); 72 } 73 } 74 75 void RenderSVGResourceContainer::idChanged() 76 { 77 // Invalidate all our current clients. 78 removeAllClientsFromCache(); 79 80 // Remove old id, that is guaranteed to be present in cache. 81 SVGDocumentExtensions* extensions = svgExtensionsFromNode(node()); 82 extensions->removeResource(m_id); 83 m_id = static_cast<Element*>(node())->getIdAttribute(); 84 85 registerResource(); 86 } 87 88 void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode) 89 { 90 if (m_clients.isEmpty()) 91 return; 92 93 bool needsLayout = mode == LayoutAndBoundariesInvalidation; 94 bool markForInvalidation = mode != ParentOnlyInvalidation; 95 96 HashSet<RenderObject*>::iterator end = m_clients.end(); 97 for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) { 98 RenderObject* client = *it; 99 if (client->isSVGResourceContainer()) { 100 client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation); 101 continue; 102 } 103 104 if (markForInvalidation) 105 markClientForInvalidation(client, mode); 106 107 if (needsLayout) 108 client->setNeedsLayout(true); 109 110 // Invalidate resources in ancestor chain, if needed. 111 RenderObject* current = client->parent(); 112 while (current) { 113 if (current->isSVGResourceContainer()) { 114 current->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation); 115 break; 116 } 117 118 current = current->parent(); 119 } 120 } 121 } 122 123 void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode) 124 { 125 ASSERT(client); 126 ASSERT(!m_clients.isEmpty()); 127 128 switch (mode) { 129 case LayoutAndBoundariesInvalidation: 130 case BoundariesInvalidation: 131 client->setNeedsBoundariesUpdate(); 132 break; 133 case RepaintInvalidation: 134 if (client->view()) 135 client->repaint(); 136 break; 137 case ParentOnlyInvalidation: 138 break; 139 } 140 } 141 142 void RenderSVGResourceContainer::addClient(RenderObject* client) 143 { 144 ASSERT(client); 145 m_clients.add(client); 146 } 147 148 void RenderSVGResourceContainer::removeClient(RenderObject* client) 149 { 150 ASSERT(client); 151 m_clients.remove(client); 152 } 153 154 void RenderSVGResourceContainer::registerResource() 155 { 156 SVGDocumentExtensions* extensions = svgExtensionsFromNode(node()); 157 if (!extensions->isPendingResource(m_id)) { 158 extensions->addResource(m_id, this); 159 return; 160 } 161 162 OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id)); 163 164 // Cache us with the new id. 165 extensions->addResource(m_id, this); 166 167 // Update cached resources of pending clients. 168 const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end(); 169 for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) { 170 RenderObject* renderer = (*it)->renderer(); 171 if (!renderer) 172 continue; 173 SVGResourcesCache::clientUpdatedFromElement(renderer, renderer->style()); 174 renderer->setNeedsLayout(true); 175 } 176 } 177 178 // FIXME: This does not belong here. 179 AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform) 180 { 181 if (!object->isSVGPath()) 182 return resourceTransform; 183 184 SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node()); 185 AffineTransform transform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate); 186 transform *= resourceTransform; 187 return transform; 188 } 189 190 } 191 192 #endif 193