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 #include "core/rendering/svg/RenderSVGResourceContainer.h"
     23 
     24 #include "core/rendering/RenderLayer.h"
     25 #include "core/rendering/RenderView.h"
     26 #include "core/rendering/svg/RenderSVGRoot.h"
     27 #include "core/rendering/svg/SVGRenderingContext.h"
     28 #include "core/rendering/svg/SVGResourcesCache.h"
     29 #include "core/svg/SVGGraphicsElement.h"
     30 
     31 namespace WebCore {
     32 
     33 static inline SVGDocumentExtensions* svgExtensionsFromNode(Node* node)
     34 {
     35     ASSERT(node);
     36     ASSERT(node->document());
     37     return node->document()->accessSVGExtensions();
     38 }
     39 
     40 RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement* node)
     41     : RenderSVGHiddenContainer(node)
     42     , m_id(node->getIdAttribute())
     43     , m_registered(false)
     44     , m_isInvalidating(false)
     45 {
     46 }
     47 
     48 RenderSVGResourceContainer::~RenderSVGResourceContainer()
     49 {
     50     if (m_registered)
     51         svgExtensionsFromNode(node())->removeResource(m_id);
     52 }
     53 
     54 void RenderSVGResourceContainer::layout()
     55 {
     56     StackStats::LayoutCheckPoint layoutCheckPoint;
     57     // Invalidate all resources if our layout changed.
     58     if (everHadLayout() && selfNeedsLayout())
     59         RenderSVGRoot::addResourceForClientInvalidation(this);
     60 
     61     RenderSVGHiddenContainer::layout();
     62 }
     63 
     64 void RenderSVGResourceContainer::willBeDestroyed()
     65 {
     66     SVGResourcesCache::resourceDestroyed(this);
     67     RenderSVGHiddenContainer::willBeDestroyed();
     68 }
     69 
     70 void RenderSVGResourceContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     71 {
     72     RenderSVGHiddenContainer::styleDidChange(diff, oldStyle);
     73 
     74     if (!m_registered) {
     75         m_registered = true;
     76         registerResource();
     77     }
     78 }
     79 
     80 void RenderSVGResourceContainer::idChanged()
     81 {
     82     // Invalidate all our current clients.
     83     removeAllClientsFromCache();
     84 
     85     // Remove old id, that is guaranteed to be present in cache.
     86     SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
     87     extensions->removeResource(m_id);
     88     m_id = toElement(node())->getIdAttribute();
     89 
     90     registerResource();
     91 }
     92 
     93 void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode)
     94 {
     95     if ((m_clients.isEmpty() && m_clientLayers.isEmpty()) || m_isInvalidating)
     96         return;
     97 
     98     m_isInvalidating = true;
     99     bool needsLayout = mode == LayoutAndBoundariesInvalidation;
    100     bool markForInvalidation = mode != ParentOnlyInvalidation;
    101 
    102     HashSet<RenderObject*>::iterator end = m_clients.end();
    103     for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) {
    104         RenderObject* client = *it;
    105         if (client->isSVGResourceContainer()) {
    106             client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation);
    107             continue;
    108         }
    109 
    110         if (markForInvalidation)
    111             markClientForInvalidation(client, mode);
    112 
    113         RenderSVGResource::markForLayoutAndParentResourceInvalidation(client, needsLayout);
    114     }
    115 
    116     markAllClientLayersForInvalidation();
    117 
    118     m_isInvalidating = false;
    119 }
    120 
    121 void RenderSVGResourceContainer::markAllClientLayersForInvalidation()
    122 {
    123     HashSet<RenderLayer*>::iterator layerEnd = m_clientLayers.end();
    124     for (HashSet<RenderLayer*>::iterator it = m_clientLayers.begin(); it != layerEnd; ++it)
    125         (*it)->filterNeedsRepaint();
    126 }
    127 
    128 void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode)
    129 {
    130     ASSERT(client);
    131     ASSERT(!m_clients.isEmpty());
    132 
    133     switch (mode) {
    134     case LayoutAndBoundariesInvalidation:
    135     case BoundariesInvalidation:
    136         client->setNeedsBoundariesUpdate();
    137         break;
    138     case RepaintInvalidation:
    139         if (client->view())
    140             client->repaint();
    141         break;
    142     case ParentOnlyInvalidation:
    143         break;
    144     }
    145 }
    146 
    147 void RenderSVGResourceContainer::addClient(RenderObject* client)
    148 {
    149     ASSERT(client);
    150     m_clients.add(client);
    151 }
    152 
    153 void RenderSVGResourceContainer::removeClient(RenderObject* client)
    154 {
    155     ASSERT(client);
    156     removeClientFromCache(client, false);
    157     m_clients.remove(client);
    158 }
    159 
    160 void RenderSVGResourceContainer::addClientRenderLayer(RenderLayer* client)
    161 {
    162     ASSERT(client);
    163     m_clientLayers.add(client);
    164 }
    165 
    166 void RenderSVGResourceContainer::removeClientRenderLayer(RenderLayer* client)
    167 {
    168     ASSERT(client);
    169     m_clientLayers.remove(client);
    170 }
    171 
    172 void RenderSVGResourceContainer::registerResource()
    173 {
    174     SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
    175     if (!extensions->hasPendingResource(m_id)) {
    176         extensions->addResource(m_id, this);
    177         return;
    178     }
    179 
    180     OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id));
    181 
    182     // Cache us with the new id.
    183     extensions->addResource(m_id, this);
    184 
    185     // Update cached resources of pending clients.
    186     const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
    187     for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
    188         ASSERT((*it)->hasPendingResources());
    189         extensions->clearHasPendingResourcesIfPossible(*it);
    190         RenderObject* renderer = (*it)->renderer();
    191         if (!renderer)
    192             continue;
    193         SVGResourcesCache::clientStyleChanged(renderer, StyleDifferenceLayout, renderer->style());
    194         renderer->setNeedsLayout();
    195     }
    196 }
    197 
    198 bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform)
    199 {
    200     ASSERT_UNUSED(object, object);
    201 
    202     // This method should only be called for RenderObjects that deal with text rendering. Cmp. RenderObject.h's is*() methods.
    203     ASSERT(object->isSVGText() || object->isSVGTextPath() || object->isSVGInline());
    204 
    205     // In text drawing, the scaling part of the graphics context CTM is removed, compare SVGInlineTextBox::paintTextWithShadows.
    206     // So, we use that scaling factor here, too, and then push it down to pattern or gradient space
    207     // in order to keep the pattern or gradient correctly scaled.
    208     float scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(object);
    209     if (scalingFactor == 1)
    210         return false;
    211     resourceTransform.scale(scalingFactor);
    212     return true;
    213 }
    214 
    215 // FIXME: This does not belong here.
    216 AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
    217 {
    218     if (!object->isSVGShape())
    219         return resourceTransform;
    220 
    221     SVGGraphicsElement* element = toSVGGraphicsElement(object->node());
    222     AffineTransform transform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate);
    223     transform *= resourceTransform;
    224     return transform;
    225 }
    226 
    227 }
    228