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