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