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