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