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