Home | History | Annotate | Download | only in svg
      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