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 #include "core/rendering/svg/SVGResources.h"
     22 
     23 #include "SVGNames.h"
     24 #include "core/rendering/style/SVGRenderStyle.h"
     25 #include "core/rendering/svg/RenderSVGResourceClipper.h"
     26 #include "core/rendering/svg/RenderSVGResourceFilter.h"
     27 #include "core/rendering/svg/RenderSVGResourceMarker.h"
     28 #include "core/rendering/svg/RenderSVGResourceMasker.h"
     29 #include "core/svg/SVGFilterElement.h"
     30 #include "core/svg/SVGGradientElement.h"
     31 #include "core/svg/SVGPaint.h"
     32 #include "core/svg/SVGPatternElement.h"
     33 #include "core/svg/SVGURIReference.h"
     34 
     35 #ifndef NDEBUG
     36 #include <stdio.h>
     37 #endif
     38 
     39 namespace WebCore {
     40 
     41 SVGResources::SVGResources()
     42     : m_linkedResource(0)
     43 {
     44 }
     45 
     46 static HashSet<AtomicString>& clipperFilterMaskerTags()
     47 {
     48     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
     49     if (s_tagList.isEmpty()) {
     50         // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
     51         // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
     52         s_tagList.add(SVGNames::aTag.localName());
     53         s_tagList.add(SVGNames::circleTag.localName());
     54         s_tagList.add(SVGNames::ellipseTag.localName());
     55         s_tagList.add(SVGNames::glyphTag.localName());
     56         s_tagList.add(SVGNames::gTag.localName());
     57         s_tagList.add(SVGNames::imageTag.localName());
     58         s_tagList.add(SVGNames::lineTag.localName());
     59         s_tagList.add(SVGNames::markerTag.localName());
     60         s_tagList.add(SVGNames::maskTag.localName());
     61         s_tagList.add(SVGNames::missing_glyphTag.localName());
     62         s_tagList.add(SVGNames::pathTag.localName());
     63         s_tagList.add(SVGNames::polygonTag.localName());
     64         s_tagList.add(SVGNames::polylineTag.localName());
     65         s_tagList.add(SVGNames::rectTag.localName());
     66         s_tagList.add(SVGNames::svgTag.localName());
     67         s_tagList.add(SVGNames::textTag.localName());
     68         s_tagList.add(SVGNames::useTag.localName());
     69 
     70         // Not listed in the definitions is the clipPath element, the SVG spec says though:
     71         // The "clipPath" element or any of its children can specify property "clip-path".
     72         // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail.
     73         // (Already mailed SVG WG, waiting for a solution)
     74         s_tagList.add(SVGNames::clipPathTag.localName());
     75 
     76         // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed.
     77         // (Already mailed SVG WG, waiting for a solution)
     78         s_tagList.add(SVGNames::altGlyphTag.localName());
     79         s_tagList.add(SVGNames::textPathTag.localName());
     80         s_tagList.add(SVGNames::trefTag.localName());
     81         s_tagList.add(SVGNames::tspanTag.localName());
     82 
     83         // Not listed in the definitions is the foreignObject element, but clip-path
     84         // is a supported attribute.
     85         s_tagList.add(SVGNames::foreignObjectTag.localName());
     86 
     87         // Elements that we ignore, as it doesn't make any sense.
     88         // defs, pattern, switch (FIXME: Mail SVG WG about these)
     89         // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.)
     90     }
     91 
     92     return s_tagList;
     93 }
     94 
     95 static HashSet<AtomicString>& markerTags()
     96 {
     97     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
     98     if (s_tagList.isEmpty()) {
     99         s_tagList.add(SVGNames::lineTag.localName());
    100         s_tagList.add(SVGNames::pathTag.localName());
    101         s_tagList.add(SVGNames::polygonTag.localName());
    102         s_tagList.add(SVGNames::polylineTag.localName());
    103     }
    104 
    105     return s_tagList;
    106 }
    107 
    108 static HashSet<AtomicString>& fillAndStrokeTags()
    109 {
    110     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
    111     if (s_tagList.isEmpty()) {
    112         s_tagList.add(SVGNames::altGlyphTag.localName());
    113         s_tagList.add(SVGNames::circleTag.localName());
    114         s_tagList.add(SVGNames::ellipseTag.localName());
    115         s_tagList.add(SVGNames::lineTag.localName());
    116         s_tagList.add(SVGNames::pathTag.localName());
    117         s_tagList.add(SVGNames::polygonTag.localName());
    118         s_tagList.add(SVGNames::polylineTag.localName());
    119         s_tagList.add(SVGNames::rectTag.localName());
    120         s_tagList.add(SVGNames::textTag.localName());
    121         s_tagList.add(SVGNames::textPathTag.localName());
    122         s_tagList.add(SVGNames::trefTag.localName());
    123         s_tagList.add(SVGNames::tspanTag.localName());
    124     }
    125 
    126     return s_tagList;
    127 }
    128 
    129 static HashSet<AtomicString>& chainableResourceTags()
    130 {
    131     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ());
    132     if (s_tagList.isEmpty()) {
    133         s_tagList.add(SVGNames::linearGradientTag.localName());
    134         s_tagList.add(SVGNames::filterTag.localName());
    135         s_tagList.add(SVGNames::patternTag.localName());
    136         s_tagList.add(SVGNames::radialGradientTag.localName());
    137     }
    138 
    139     return s_tagList;
    140 }
    141 
    142 static inline String targetReferenceFromResource(SVGElement* element)
    143 {
    144     String target;
    145     if (element->hasTagName(SVGNames::patternTag))
    146         target = toSVGPatternElement(element)->hrefCurrentValue();
    147     else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
    148         target = toSVGGradientElement(element)->hrefCurrentValue();
    149     else if (element->hasTagName(SVGNames::filterTag))
    150         target = toSVGFilterElement(element)->hrefCurrentValue();
    151     else
    152         ASSERT_NOT_REACHED();
    153 
    154     return SVGURIReference::fragmentIdentifierFromIRIString(target, element->document());
    155 }
    156 
    157 static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource)
    158 {
    159     if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
    160         return 0;
    161 
    162     id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document);
    163     RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id);
    164     if (!container) {
    165         hasPendingResource = true;
    166         return 0;
    167     }
    168 
    169     RenderSVGResourceType resourceType = container->resourceType();
    170     if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType)
    171         return 0;
    172 
    173     return container;
    174 }
    175 
    176 static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element)
    177 {
    178     ASSERT(element);
    179     extensions->addPendingResource(id, element);
    180 }
    181 
    182 bool SVGResources::buildResources(const RenderObject* object, const SVGRenderStyle* style)
    183 {
    184     ASSERT(object);
    185     ASSERT(style);
    186 
    187     Node* node = object->node();
    188     ASSERT(node);
    189     ASSERT_WITH_SECURITY_IMPLICATION(node->isSVGElement());
    190 
    191     SVGElement* element = toSVGElement(node);
    192     if (!element)
    193         return false;
    194 
    195     Document* document = object->document();
    196     ASSERT(document);
    197 
    198     SVGDocumentExtensions* extensions = document->accessSVGExtensions();
    199     ASSERT(extensions);
    200 
    201     const AtomicString& tagName = element->localName();
    202     if (tagName.isNull())
    203         return false;
    204 
    205     bool foundResources = false;
    206     if (clipperFilterMaskerTags().contains(tagName)) {
    207         if (style->hasClipper()) {
    208             AtomicString id(style->clipperResource());
    209             if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id)))
    210                 foundResources = true;
    211             else
    212                 registerPendingResource(extensions, id, element);
    213         }
    214 
    215         if (style->hasFilter()) {
    216             AtomicString id(style->filterResource());
    217             if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id)))
    218                 foundResources = true;
    219             else
    220                 registerPendingResource(extensions, id, element);
    221         }
    222 
    223         if (style->hasMasker()) {
    224             AtomicString id(style->maskerResource());
    225             if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id)))
    226                 foundResources = true;
    227             else
    228                 registerPendingResource(extensions, id, element);
    229         }
    230     }
    231 
    232     if (markerTags().contains(tagName) && style->hasMarkers()) {
    233         AtomicString markerStartId(style->markerStartResource());
    234         if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId)))
    235             foundResources = true;
    236         else
    237             registerPendingResource(extensions, markerStartId, element);
    238 
    239         AtomicString markerMidId(style->markerMidResource());
    240         if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId)))
    241             foundResources = true;
    242         else
    243             registerPendingResource(extensions, markerMidId, element);
    244 
    245         AtomicString markerEndId(style->markerEndResource());
    246         if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId)))
    247             foundResources = true;
    248         else
    249             registerPendingResource(extensions, markerEndId, element);
    250     }
    251 
    252     if (fillAndStrokeTags().contains(tagName)) {
    253         if (style->hasFill()) {
    254             bool hasPendingResource = false;
    255             AtomicString id;
    256             if (setFill(paintingResourceFromSVGPaint(document, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource)))
    257                 foundResources = true;
    258             else if (hasPendingResource)
    259                 registerPendingResource(extensions, id, element);
    260         }
    261 
    262         if (style->hasStroke()) {
    263             bool hasPendingResource = false;
    264             AtomicString id;
    265             if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource)))
    266                 foundResources = true;
    267             else if (hasPendingResource)
    268                 registerPendingResource(extensions, id, element);
    269         }
    270     }
    271 
    272     if (chainableResourceTags().contains(tagName)) {
    273         AtomicString id(targetReferenceFromResource(element));
    274         if (setLinkedResource(getRenderSVGResourceContainerById(document, id)))
    275             foundResources = true;
    276         else
    277             registerPendingResource(extensions, id, element);
    278     }
    279 
    280     return foundResources;
    281 }
    282 
    283 void SVGResources::removeClientFromCache(RenderObject* object, bool markForInvalidation) const
    284 {
    285     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
    286         return;
    287 
    288     if (m_linkedResource) {
    289         ASSERT(!m_clipperFilterMaskerData);
    290         ASSERT(!m_markerData);
    291         ASSERT(!m_fillStrokeData);
    292         m_linkedResource->removeClientFromCache(object, markForInvalidation);
    293         return;
    294     }
    295 
    296     if (m_clipperFilterMaskerData) {
    297         if (m_clipperFilterMaskerData->clipper)
    298             m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation);
    299         if (m_clipperFilterMaskerData->filter)
    300             m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation);
    301         if (m_clipperFilterMaskerData->masker)
    302             m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation);
    303     }
    304 
    305     if (m_markerData) {
    306         if (m_markerData->markerStart)
    307             m_markerData->markerStart->removeClientFromCache(object, markForInvalidation);
    308         if (m_markerData->markerMid)
    309             m_markerData->markerMid->removeClientFromCache(object, markForInvalidation);
    310         if (m_markerData->markerEnd)
    311             m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation);
    312     }
    313 
    314     if (m_fillStrokeData) {
    315         if (m_fillStrokeData->fill)
    316             m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation);
    317         if (m_fillStrokeData->stroke)
    318             m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation);
    319     }
    320 }
    321 
    322 void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource)
    323 {
    324     ASSERT(resource);
    325     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
    326         return;
    327 
    328     if (m_linkedResource == resource) {
    329         ASSERT(!m_clipperFilterMaskerData);
    330         ASSERT(!m_markerData);
    331         ASSERT(!m_fillStrokeData);
    332         m_linkedResource->removeAllClientsFromCache();
    333         m_linkedResource = 0;
    334         return;
    335     }
    336 
    337     switch (resource->resourceType()) {
    338     case MaskerResourceType:
    339         if (!m_clipperFilterMaskerData)
    340             break;
    341         if (m_clipperFilterMaskerData->masker == resource) {
    342             m_clipperFilterMaskerData->masker->removeAllClientsFromCache();
    343             m_clipperFilterMaskerData->masker = 0;
    344         }
    345         break;
    346     case MarkerResourceType:
    347         if (!m_markerData)
    348             break;
    349         if (m_markerData->markerStart == resource) {
    350             m_markerData->markerStart->removeAllClientsFromCache();
    351             m_markerData->markerStart = 0;
    352         }
    353         if (m_markerData->markerMid == resource) {
    354             m_markerData->markerMid->removeAllClientsFromCache();
    355             m_markerData->markerMid = 0;
    356         }
    357         if (m_markerData->markerEnd == resource) {
    358             m_markerData->markerEnd->removeAllClientsFromCache();
    359             m_markerData->markerEnd = 0;
    360         }
    361         break;
    362     case PatternResourceType:
    363     case LinearGradientResourceType:
    364     case RadialGradientResourceType:
    365         if (!m_fillStrokeData)
    366             break;
    367         if (m_fillStrokeData->fill == resource) {
    368             m_fillStrokeData->fill->removeAllClientsFromCache();
    369             m_fillStrokeData->fill = 0;
    370         }
    371         if (m_fillStrokeData->stroke == resource) {
    372             m_fillStrokeData->stroke->removeAllClientsFromCache();
    373             m_fillStrokeData->stroke = 0;
    374         }
    375         break;
    376     case FilterResourceType:
    377         if (!m_clipperFilterMaskerData)
    378             break;
    379         if (m_clipperFilterMaskerData->filter == resource) {
    380             m_clipperFilterMaskerData->filter->removeAllClientsFromCache();
    381             m_clipperFilterMaskerData->filter = 0;
    382         }
    383         break;
    384     case ClipperResourceType:
    385         if (!m_clipperFilterMaskerData)
    386             break;
    387         if (m_clipperFilterMaskerData->clipper == resource) {
    388             m_clipperFilterMaskerData->clipper->removeAllClientsFromCache();
    389             m_clipperFilterMaskerData->clipper = 0;
    390         }
    391         break;
    392     case SolidColorResourceType:
    393         ASSERT_NOT_REACHED();
    394     }
    395 }
    396 
    397 void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
    398 {
    399     if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource)
    400         return;
    401 
    402     if (m_linkedResource) {
    403         ASSERT(!m_clipperFilterMaskerData);
    404         ASSERT(!m_markerData);
    405         ASSERT(!m_fillStrokeData);
    406         set.add(m_linkedResource);
    407         return;
    408     }
    409 
    410     if (m_clipperFilterMaskerData) {
    411         if (m_clipperFilterMaskerData->clipper)
    412             set.add(m_clipperFilterMaskerData->clipper);
    413         if (m_clipperFilterMaskerData->filter)
    414             set.add(m_clipperFilterMaskerData->filter);
    415         if (m_clipperFilterMaskerData->masker)
    416             set.add(m_clipperFilterMaskerData->masker);
    417     }
    418 
    419     if (m_markerData) {
    420         if (m_markerData->markerStart)
    421             set.add(m_markerData->markerStart);
    422         if (m_markerData->markerMid)
    423             set.add(m_markerData->markerMid);
    424         if (m_markerData->markerEnd)
    425             set.add(m_markerData->markerEnd);
    426     }
    427 
    428     if (m_fillStrokeData) {
    429         if (m_fillStrokeData->fill)
    430             set.add(m_fillStrokeData->fill);
    431         if (m_fillStrokeData->stroke)
    432             set.add(m_fillStrokeData->stroke);
    433     }
    434 }
    435 
    436 bool SVGResources::setClipper(RenderSVGResourceClipper* clipper)
    437 {
    438     if (!clipper)
    439         return false;
    440 
    441     ASSERT(clipper->resourceType() == ClipperResourceType);
    442 
    443     if (!m_clipperFilterMaskerData)
    444         m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
    445 
    446     m_clipperFilterMaskerData->clipper = clipper;
    447     return true;
    448 }
    449 
    450 void SVGResources::resetClipper()
    451 {
    452     ASSERT(m_clipperFilterMaskerData);
    453     ASSERT(m_clipperFilterMaskerData->clipper);
    454     m_clipperFilterMaskerData->clipper = 0;
    455 }
    456 
    457 bool SVGResources::setFilter(RenderSVGResourceFilter* filter)
    458 {
    459     if (!filter)
    460         return false;
    461 
    462     ASSERT(filter->resourceType() == FilterResourceType);
    463 
    464     if (!m_clipperFilterMaskerData)
    465         m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
    466 
    467     m_clipperFilterMaskerData->filter = filter;
    468     return true;
    469 }
    470 
    471 void SVGResources::resetFilter()
    472 {
    473     ASSERT(m_clipperFilterMaskerData);
    474     ASSERT(m_clipperFilterMaskerData->filter);
    475     m_clipperFilterMaskerData->filter = 0;
    476 }
    477 
    478 bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart)
    479 {
    480     if (!markerStart)
    481         return false;
    482 
    483     ASSERT(markerStart->resourceType() == MarkerResourceType);
    484 
    485     if (!m_markerData)
    486         m_markerData = MarkerData::create();
    487 
    488     m_markerData->markerStart = markerStart;
    489     return true;
    490 }
    491 
    492 void SVGResources::resetMarkerStart()
    493 {
    494     ASSERT(m_markerData);
    495     ASSERT(m_markerData->markerStart);
    496     m_markerData->markerStart = 0;
    497 }
    498 
    499 bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid)
    500 {
    501     if (!markerMid)
    502         return false;
    503 
    504     ASSERT(markerMid->resourceType() == MarkerResourceType);
    505 
    506     if (!m_markerData)
    507         m_markerData = MarkerData::create();
    508 
    509     m_markerData->markerMid = markerMid;
    510     return true;
    511 }
    512 
    513 void SVGResources::resetMarkerMid()
    514 {
    515     ASSERT(m_markerData);
    516     ASSERT(m_markerData->markerMid);
    517     m_markerData->markerMid = 0;
    518 }
    519 
    520 bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd)
    521 {
    522     if (!markerEnd)
    523         return false;
    524 
    525     ASSERT(markerEnd->resourceType() == MarkerResourceType);
    526 
    527     if (!m_markerData)
    528         m_markerData = MarkerData::create();
    529 
    530     m_markerData->markerEnd = markerEnd;
    531     return true;
    532 }
    533 
    534 void SVGResources::resetMarkerEnd()
    535 {
    536     ASSERT(m_markerData);
    537     ASSERT(m_markerData->markerEnd);
    538     m_markerData->markerEnd = 0;
    539 }
    540 
    541 bool SVGResources::setMasker(RenderSVGResourceMasker* masker)
    542 {
    543     if (!masker)
    544         return false;
    545 
    546     ASSERT(masker->resourceType() == MaskerResourceType);
    547 
    548     if (!m_clipperFilterMaskerData)
    549         m_clipperFilterMaskerData = ClipperFilterMaskerData::create();
    550 
    551     m_clipperFilterMaskerData->masker = masker;
    552     return true;
    553 }
    554 
    555 void SVGResources::resetMasker()
    556 {
    557     ASSERT(m_clipperFilterMaskerData);
    558     ASSERT(m_clipperFilterMaskerData->masker);
    559     m_clipperFilterMaskerData->masker = 0;
    560 }
    561 
    562 bool SVGResources::setFill(RenderSVGResourceContainer* fill)
    563 {
    564     if (!fill)
    565         return false;
    566 
    567     ASSERT(fill->resourceType() == PatternResourceType
    568            || fill->resourceType() == LinearGradientResourceType
    569            || fill->resourceType() == RadialGradientResourceType);
    570 
    571     if (!m_fillStrokeData)
    572         m_fillStrokeData = FillStrokeData::create();
    573 
    574     m_fillStrokeData->fill = fill;
    575     return true;
    576 }
    577 
    578 void SVGResources::resetFill()
    579 {
    580     ASSERT(m_fillStrokeData);
    581     ASSERT(m_fillStrokeData->fill);
    582     m_fillStrokeData->fill = 0;
    583 }
    584 
    585 bool SVGResources::setStroke(RenderSVGResourceContainer* stroke)
    586 {
    587     if (!stroke)
    588         return false;
    589 
    590     ASSERT(stroke->resourceType() == PatternResourceType
    591            || stroke->resourceType() == LinearGradientResourceType
    592            || stroke->resourceType() == RadialGradientResourceType);
    593 
    594     if (!m_fillStrokeData)
    595         m_fillStrokeData = FillStrokeData::create();
    596 
    597     m_fillStrokeData->stroke = stroke;
    598     return true;
    599 }
    600 
    601 void SVGResources::resetStroke()
    602 {
    603     ASSERT(m_fillStrokeData);
    604     ASSERT(m_fillStrokeData->stroke);
    605     m_fillStrokeData->stroke = 0;
    606 }
    607 
    608 bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource)
    609 {
    610     if (!linkedResource)
    611         return false;
    612 
    613     m_linkedResource = linkedResource;
    614     return true;
    615 }
    616 
    617 void SVGResources::resetLinkedResource()
    618 {
    619     ASSERT(m_linkedResource);
    620     m_linkedResource = 0;
    621 }
    622 
    623 #ifndef NDEBUG
    624 void SVGResources::dump(const RenderObject* object)
    625 {
    626     ASSERT(object);
    627     ASSERT(object->node());
    628 
    629     fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
    630     fprintf(stderr, " | DOM Tree:\n");
    631     object->node()->showTreeForThis();
    632 
    633     fprintf(stderr, "\n | List of resources:\n");
    634     if (m_clipperFilterMaskerData) {
    635         if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper)
    636             fprintf(stderr, " |-> Clipper    : %p (node=%p)\n", clipper, clipper->node());
    637         if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter)
    638             fprintf(stderr, " |-> Filter     : %p (node=%p)\n", filter, filter->node());
    639         if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker)
    640             fprintf(stderr, " |-> Masker     : %p (node=%p)\n", masker, masker->node());
    641     }
    642 
    643     if (m_markerData) {
    644         if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart)
    645             fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->node());
    646         if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid)
    647             fprintf(stderr, " |-> MarkerMid  : %p (node=%p)\n", markerMid, markerMid->node());
    648         if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd)
    649             fprintf(stderr, " |-> MarkerEnd  : %p (node=%p)\n", markerEnd, markerEnd->node());
    650     }
    651 
    652     if (m_fillStrokeData) {
    653         if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill)
    654             fprintf(stderr, " |-> Fill       : %p (node=%p)\n", fill, fill->node());
    655         if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke)
    656             fprintf(stderr, " |-> Stroke     : %p (node=%p)\n", stroke, stroke->node());
    657     }
    658 
    659     if (m_linkedResource)
    660         fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->node());
    661 }
    662 #endif
    663 
    664 }
    665