| /* |
| * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "core/layout/svg/SVGResources.h" |
| |
| #include "core/SVGNames.h" |
| #include "core/layout/svg/LayoutSVGResourceClipper.h" |
| #include "core/layout/svg/LayoutSVGResourceFilter.h" |
| #include "core/layout/svg/LayoutSVGResourceMarker.h" |
| #include "core/layout/svg/LayoutSVGResourceMasker.h" |
| #include "core/layout/svg/LayoutSVGResourcePaintServer.h" |
| #include "core/style/ComputedStyle.h" |
| #include "core/svg/SVGFilterElement.h" |
| #include "core/svg/SVGGradientElement.h" |
| #include "core/svg/SVGPatternElement.h" |
| #include "core/svg/SVGURIReference.h" |
| #include "wtf/PtrUtil.h" |
| #include <memory> |
| |
| #ifndef NDEBUG |
| #include <stdio.h> |
| #endif |
| |
| namespace blink { |
| |
| using namespace SVGNames; |
| |
| SVGResources::SVGResources() |
| : m_linkedResource(nullptr) |
| { |
| } |
| |
| static HashSet<AtomicString>& clipperFilterMaskerTags() |
| { |
| DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); |
| if (s_tagList.isEmpty()) { |
| // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement |
| // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement |
| s_tagList.add(aTag.localName()); |
| s_tagList.add(circleTag.localName()); |
| s_tagList.add(ellipseTag.localName()); |
| s_tagList.add(gTag.localName()); |
| s_tagList.add(imageTag.localName()); |
| s_tagList.add(lineTag.localName()); |
| s_tagList.add(markerTag.localName()); |
| s_tagList.add(maskTag.localName()); |
| s_tagList.add(pathTag.localName()); |
| s_tagList.add(polygonTag.localName()); |
| s_tagList.add(polylineTag.localName()); |
| s_tagList.add(rectTag.localName()); |
| s_tagList.add(svgTag.localName()); |
| s_tagList.add(textTag.localName()); |
| s_tagList.add(useTag.localName()); |
| |
| // Not listed in the definitions is the clipPath element, the SVG spec says though: |
| // The "clipPath" element or any of its children can specify property "clip-path". |
| // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail. |
| // (Already mailed SVG WG, waiting for a solution) |
| s_tagList.add(clipPathTag.localName()); |
| |
| // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed. |
| // (Already mailed SVG WG, waiting for a solution) |
| s_tagList.add(textPathTag.localName()); |
| s_tagList.add(tspanTag.localName()); |
| |
| // Not listed in the definitions is the foreignObject element, but clip-path |
| // is a supported attribute. |
| s_tagList.add(foreignObjectTag.localName()); |
| |
| // Elements that we ignore, as it doesn't make any sense. |
| // defs, pattern, switch (FIXME: Mail SVG WG about these) |
| // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.) |
| } |
| |
| return s_tagList; |
| } |
| |
| bool SVGResources::supportsMarkers(const SVGElement& element) |
| { |
| DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); |
| if (s_tagList.isEmpty()) { |
| s_tagList.add(lineTag.localName()); |
| s_tagList.add(pathTag.localName()); |
| s_tagList.add(polygonTag.localName()); |
| s_tagList.add(polylineTag.localName()); |
| } |
| |
| return s_tagList.contains(element.localName()); |
| } |
| |
| static HashSet<AtomicString>& fillAndStrokeTags() |
| { |
| DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); |
| if (s_tagList.isEmpty()) { |
| s_tagList.add(circleTag.localName()); |
| s_tagList.add(ellipseTag.localName()); |
| s_tagList.add(lineTag.localName()); |
| s_tagList.add(pathTag.localName()); |
| s_tagList.add(polygonTag.localName()); |
| s_tagList.add(polylineTag.localName()); |
| s_tagList.add(rectTag.localName()); |
| s_tagList.add(textTag.localName()); |
| s_tagList.add(textPathTag.localName()); |
| s_tagList.add(tspanTag.localName()); |
| } |
| |
| return s_tagList; |
| } |
| |
| static HashSet<AtomicString>& chainableResourceTags() |
| { |
| DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); |
| if (s_tagList.isEmpty()) { |
| s_tagList.add(linearGradientTag.localName()); |
| s_tagList.add(filterTag.localName()); |
| s_tagList.add(patternTag.localName()); |
| s_tagList.add(radialGradientTag.localName()); |
| } |
| |
| return s_tagList; |
| } |
| |
| static inline AtomicString targetReferenceFromResource(SVGElement& element) |
| { |
| String target; |
| if (isSVGPatternElement(element)) |
| target = toSVGPatternElement(element).href()->currentValue()->value(); |
| else if (isSVGGradientElement(element)) |
| target = toSVGGradientElement(element).href()->currentValue()->value(); |
| else if (isSVGFilterElement(element)) |
| target = toSVGFilterElement(element).href()->currentValue()->value(); |
| else |
| ASSERT_NOT_REACHED(); |
| |
| return SVGURIReference::fragmentIdentifierFromIRIString(target, element.treeScope()); |
| } |
| |
| static inline bool svgPaintTypeHasURL(SVGPaintType paintType) |
| { |
| switch (paintType) { |
| case SVG_PAINTTYPE_URI_NONE: |
| case SVG_PAINTTYPE_URI_CURRENTCOLOR: |
| case SVG_PAINTTYPE_URI_RGBCOLOR: |
| case SVG_PAINTTYPE_URI: |
| return true; |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| static inline LayoutSVGResourcePaintServer* paintingResourceFromSVGPaint(TreeScope& treeScope, const SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) |
| { |
| if (!svgPaintTypeHasURL(paintType)) |
| return nullptr; |
| |
| id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, treeScope); |
| LayoutSVGResourceContainer* container = getLayoutSVGResourceContainerById(treeScope, id); |
| if (!container) { |
| hasPendingResource = true; |
| return nullptr; |
| } |
| |
| if (!container->isSVGPaintServer()) |
| return nullptr; |
| |
| return toLayoutSVGResourcePaintServer(container); |
| } |
| |
| static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement* element) |
| { |
| ASSERT(element); |
| extensions.addPendingResource(id, element); |
| } |
| |
| bool SVGResources::hasResourceData() const |
| { |
| return m_clipperFilterMaskerData |
| || m_markerData |
| || m_fillStrokeData |
| || m_linkedResource; |
| } |
| |
| static inline SVGResources& ensureResources(std::unique_ptr<SVGResources>& resources) |
| { |
| if (!resources) |
| resources = wrapUnique(new SVGResources); |
| |
| return *resources.get(); |
| } |
| |
| std::unique_ptr<SVGResources> SVGResources::buildResources(const LayoutObject* object, const ComputedStyle& computedStyle) |
| { |
| ASSERT(object); |
| |
| Node* node = object->node(); |
| ASSERT(node); |
| ASSERT_WITH_SECURITY_IMPLICATION(node->isSVGElement()); |
| |
| SVGElement* element = toSVGElement(node); |
| ASSERT(element); |
| |
| const AtomicString& tagName = element->localName(); |
| ASSERT(!tagName.isNull()); |
| |
| TreeScope& treeScope = element->treeScope(); |
| SVGDocumentExtensions& extensions = element->document().accessSVGExtensions(); |
| |
| const SVGComputedStyle& style = computedStyle.svgStyle(); |
| |
| std::unique_ptr<SVGResources> resources; |
| if (clipperFilterMaskerTags().contains(tagName)) { |
| if (style.hasClipper()) { |
| AtomicString id = style.clipperResource(); |
| if (!ensureResources(resources).setClipper(getLayoutSVGResourceById<LayoutSVGResourceClipper>(treeScope, id))) |
| registerPendingResource(extensions, id, element); |
| } |
| |
| if (computedStyle.hasFilter() && !object->isSVGRoot()) { |
| const FilterOperations& filterOperations = computedStyle.filter(); |
| if (filterOperations.size() == 1) { |
| const FilterOperation& filterOperation = *filterOperations.at(0); |
| if (filterOperation.type() == FilterOperation::REFERENCE) { |
| const auto& referenceFilterOperation = toReferenceFilterOperation(filterOperation); |
| AtomicString id = SVGURIReference::fragmentIdentifierFromIRIString(referenceFilterOperation.url(), treeScope); |
| if (!ensureResources(resources).setFilter(getLayoutSVGResourceById<LayoutSVGResourceFilter>(treeScope, id))) |
| registerPendingResource(extensions, id, element); |
| } |
| } |
| } |
| |
| if (style.hasMasker()) { |
| AtomicString id = style.maskerResource(); |
| if (!ensureResources(resources).setMasker(getLayoutSVGResourceById<LayoutSVGResourceMasker>(treeScope, id))) |
| registerPendingResource(extensions, id, element); |
| } |
| } |
| |
| if (style.hasMarkers() && supportsMarkers(*element)) { |
| const AtomicString& markerStartId = style.markerStartResource(); |
| if (!ensureResources(resources).setMarkerStart(getLayoutSVGResourceById<LayoutSVGResourceMarker>(treeScope, markerStartId))) |
| registerPendingResource(extensions, markerStartId, element); |
| |
| const AtomicString& markerMidId = style.markerMidResource(); |
| if (!ensureResources(resources).setMarkerMid(getLayoutSVGResourceById<LayoutSVGResourceMarker>(treeScope, markerMidId))) |
| registerPendingResource(extensions, markerMidId, element); |
| |
| const AtomicString& markerEndId = style.markerEndResource(); |
| if (!ensureResources(resources).setMarkerEnd(getLayoutSVGResourceById<LayoutSVGResourceMarker>(treeScope, style.markerEndResource()))) |
| registerPendingResource(extensions, markerEndId, element); |
| } |
| |
| if (fillAndStrokeTags().contains(tagName)) { |
| if (style.hasFill()) { |
| bool hasPendingResource = false; |
| AtomicString id; |
| LayoutSVGResourcePaintServer* resource = paintingResourceFromSVGPaint(treeScope, style.fillPaintType(), style.fillPaintUri(), id, hasPendingResource); |
| if (!ensureResources(resources).setFill(resource) && hasPendingResource) |
| registerPendingResource(extensions, id, element); |
| } |
| |
| if (style.hasStroke()) { |
| bool hasPendingResource = false; |
| AtomicString id; |
| LayoutSVGResourcePaintServer* resource = paintingResourceFromSVGPaint(treeScope, style.strokePaintType(), style.strokePaintUri(), id, hasPendingResource); |
| if (!ensureResources(resources).setStroke(resource) && hasPendingResource) |
| registerPendingResource(extensions, id, element); |
| } |
| } |
| |
| if (chainableResourceTags().contains(tagName)) { |
| AtomicString id = targetReferenceFromResource(*element); |
| if (!ensureResources(resources).setLinkedResource(getLayoutSVGResourceContainerById(treeScope, id))) |
| registerPendingResource(extensions, id, element); |
| } |
| |
| return (!resources || !resources->hasResourceData()) ? nullptr : std::move(resources); |
| } |
| |
| void SVGResources::layoutIfNeeded() |
| { |
| if (m_clipperFilterMaskerData) { |
| if (LayoutSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper) |
| clipper->layoutIfNeeded(); |
| if (LayoutSVGResourceMasker* masker = m_clipperFilterMaskerData->masker) |
| masker->layoutIfNeeded(); |
| if (LayoutSVGResourceFilter* filter = m_clipperFilterMaskerData->filter) |
| filter->layoutIfNeeded(); |
| } |
| |
| if (m_markerData) { |
| if (LayoutSVGResourceMarker* marker = m_markerData->markerStart) |
| marker->layoutIfNeeded(); |
| if (LayoutSVGResourceMarker* marker = m_markerData->markerMid) |
| marker->layoutIfNeeded(); |
| if (LayoutSVGResourceMarker* marker = m_markerData->markerEnd) |
| marker->layoutIfNeeded(); |
| } |
| |
| if (m_fillStrokeData) { |
| if (LayoutSVGResourcePaintServer* fill = m_fillStrokeData->fill) |
| fill->layoutIfNeeded(); |
| if (LayoutSVGResourcePaintServer* stroke = m_fillStrokeData->stroke) |
| stroke->layoutIfNeeded(); |
| } |
| |
| if (m_linkedResource) |
| m_linkedResource->layoutIfNeeded(); |
| } |
| |
| void SVGResources::removeClientFromCache(LayoutObject* object, bool markForInvalidation) const |
| { |
| if (!hasResourceData()) |
| return; |
| |
| if (m_linkedResource) { |
| ASSERT(!m_clipperFilterMaskerData); |
| ASSERT(!m_markerData); |
| ASSERT(!m_fillStrokeData); |
| m_linkedResource->removeClientFromCache(object, markForInvalidation); |
| return; |
| } |
| |
| if (m_clipperFilterMaskerData) { |
| if (m_clipperFilterMaskerData->clipper) |
| m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation); |
| if (m_clipperFilterMaskerData->filter) |
| m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation); |
| if (m_clipperFilterMaskerData->masker) |
| m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation); |
| } |
| |
| if (m_markerData) { |
| if (m_markerData->markerStart) |
| m_markerData->markerStart->removeClientFromCache(object, markForInvalidation); |
| if (m_markerData->markerMid) |
| m_markerData->markerMid->removeClientFromCache(object, markForInvalidation); |
| if (m_markerData->markerEnd) |
| m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation); |
| } |
| |
| if (m_fillStrokeData) { |
| if (m_fillStrokeData->fill) |
| m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation); |
| if (m_fillStrokeData->stroke) |
| m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation); |
| } |
| } |
| |
| void SVGResources::resourceDestroyed(LayoutSVGResourceContainer* resource) |
| { |
| ASSERT(resource); |
| if (!hasResourceData()) |
| return; |
| |
| if (m_linkedResource == resource) { |
| ASSERT(!m_clipperFilterMaskerData); |
| ASSERT(!m_markerData); |
| ASSERT(!m_fillStrokeData); |
| m_linkedResource->removeAllClientsFromCache(); |
| m_linkedResource = nullptr; |
| return; |
| } |
| |
| switch (resource->resourceType()) { |
| case MaskerResourceType: |
| if (!m_clipperFilterMaskerData) |
| break; |
| if (m_clipperFilterMaskerData->masker == resource) |
| m_clipperFilterMaskerData->masker = nullptr; |
| break; |
| case MarkerResourceType: |
| if (!m_markerData) |
| break; |
| if (m_markerData->markerStart == resource) |
| m_markerData->markerStart = nullptr; |
| if (m_markerData->markerMid == resource) |
| m_markerData->markerMid = nullptr; |
| if (m_markerData->markerEnd == resource) |
| m_markerData->markerEnd = nullptr; |
| break; |
| case PatternResourceType: |
| case LinearGradientResourceType: |
| case RadialGradientResourceType: |
| if (!m_fillStrokeData) |
| break; |
| if (m_fillStrokeData->fill == resource) |
| m_fillStrokeData->fill = nullptr; |
| if (m_fillStrokeData->stroke == resource) |
| m_fillStrokeData->stroke = nullptr; |
| break; |
| case FilterResourceType: |
| if (!m_clipperFilterMaskerData) |
| break; |
| if (m_clipperFilterMaskerData->filter == resource) |
| m_clipperFilterMaskerData->filter = nullptr; |
| break; |
| case ClipperResourceType: |
| if (!m_clipperFilterMaskerData) |
| break; |
| if (m_clipperFilterMaskerData->clipper == resource) |
| m_clipperFilterMaskerData->clipper = nullptr; |
| break; |
| default: |
| ASSERT_NOT_REACHED(); |
| } |
| } |
| |
| void SVGResources::buildSetOfResources(HashSet<LayoutSVGResourceContainer*>& set) |
| { |
| if (!hasResourceData()) |
| return; |
| |
| if (m_linkedResource) { |
| ASSERT(!m_clipperFilterMaskerData); |
| ASSERT(!m_markerData); |
| ASSERT(!m_fillStrokeData); |
| set.add(m_linkedResource); |
| return; |
| } |
| |
| if (m_clipperFilterMaskerData) { |
| if (m_clipperFilterMaskerData->clipper) |
| set.add(m_clipperFilterMaskerData->clipper); |
| if (m_clipperFilterMaskerData->filter) |
| set.add(m_clipperFilterMaskerData->filter); |
| if (m_clipperFilterMaskerData->masker) |
| set.add(m_clipperFilterMaskerData->masker); |
| } |
| |
| if (m_markerData) { |
| if (m_markerData->markerStart) |
| set.add(m_markerData->markerStart); |
| if (m_markerData->markerMid) |
| set.add(m_markerData->markerMid); |
| if (m_markerData->markerEnd) |
| set.add(m_markerData->markerEnd); |
| } |
| |
| if (m_fillStrokeData) { |
| if (m_fillStrokeData->fill) |
| set.add(m_fillStrokeData->fill); |
| if (m_fillStrokeData->stroke) |
| set.add(m_fillStrokeData->stroke); |
| } |
| } |
| |
| bool SVGResources::setClipper(LayoutSVGResourceClipper* clipper) |
| { |
| if (!clipper) |
| return false; |
| |
| ASSERT(clipper->resourceType() == ClipperResourceType); |
| |
| if (!m_clipperFilterMaskerData) |
| m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); |
| |
| m_clipperFilterMaskerData->clipper = clipper; |
| return true; |
| } |
| |
| void SVGResources::resetClipper() |
| { |
| ASSERT(m_clipperFilterMaskerData); |
| ASSERT(m_clipperFilterMaskerData->clipper); |
| m_clipperFilterMaskerData->clipper = nullptr; |
| } |
| |
| bool SVGResources::setFilter(LayoutSVGResourceFilter* filter) |
| { |
| if (!filter) |
| return false; |
| |
| ASSERT(filter->resourceType() == FilterResourceType); |
| |
| if (!m_clipperFilterMaskerData) |
| m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); |
| |
| m_clipperFilterMaskerData->filter = filter; |
| return true; |
| } |
| |
| void SVGResources::resetFilter() |
| { |
| ASSERT(m_clipperFilterMaskerData); |
| ASSERT(m_clipperFilterMaskerData->filter); |
| m_clipperFilterMaskerData->filter = nullptr; |
| } |
| |
| bool SVGResources::setMarkerStart(LayoutSVGResourceMarker* markerStart) |
| { |
| if (!markerStart) |
| return false; |
| |
| ASSERT(markerStart->resourceType() == MarkerResourceType); |
| |
| if (!m_markerData) |
| m_markerData = MarkerData::create(); |
| |
| m_markerData->markerStart = markerStart; |
| return true; |
| } |
| |
| void SVGResources::resetMarkerStart() |
| { |
| ASSERT(m_markerData); |
| ASSERT(m_markerData->markerStart); |
| m_markerData->markerStart = nullptr; |
| } |
| |
| bool SVGResources::setMarkerMid(LayoutSVGResourceMarker* markerMid) |
| { |
| if (!markerMid) |
| return false; |
| |
| ASSERT(markerMid->resourceType() == MarkerResourceType); |
| |
| if (!m_markerData) |
| m_markerData = MarkerData::create(); |
| |
| m_markerData->markerMid = markerMid; |
| return true; |
| } |
| |
| void SVGResources::resetMarkerMid() |
| { |
| ASSERT(m_markerData); |
| ASSERT(m_markerData->markerMid); |
| m_markerData->markerMid = nullptr; |
| } |
| |
| bool SVGResources::setMarkerEnd(LayoutSVGResourceMarker* markerEnd) |
| { |
| if (!markerEnd) |
| return false; |
| |
| ASSERT(markerEnd->resourceType() == MarkerResourceType); |
| |
| if (!m_markerData) |
| m_markerData = MarkerData::create(); |
| |
| m_markerData->markerEnd = markerEnd; |
| return true; |
| } |
| |
| void SVGResources::resetMarkerEnd() |
| { |
| ASSERT(m_markerData); |
| ASSERT(m_markerData->markerEnd); |
| m_markerData->markerEnd = nullptr; |
| } |
| |
| bool SVGResources::setMasker(LayoutSVGResourceMasker* masker) |
| { |
| if (!masker) |
| return false; |
| |
| ASSERT(masker->resourceType() == MaskerResourceType); |
| |
| if (!m_clipperFilterMaskerData) |
| m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); |
| |
| m_clipperFilterMaskerData->masker = masker; |
| return true; |
| } |
| |
| void SVGResources::resetMasker() |
| { |
| ASSERT(m_clipperFilterMaskerData); |
| ASSERT(m_clipperFilterMaskerData->masker); |
| m_clipperFilterMaskerData->masker = nullptr; |
| } |
| |
| bool SVGResources::setFill(LayoutSVGResourcePaintServer* fill) |
| { |
| if (!fill) |
| return false; |
| |
| if (!m_fillStrokeData) |
| m_fillStrokeData = FillStrokeData::create(); |
| |
| m_fillStrokeData->fill = fill; |
| return true; |
| } |
| |
| void SVGResources::resetFill() |
| { |
| ASSERT(m_fillStrokeData); |
| ASSERT(m_fillStrokeData->fill); |
| m_fillStrokeData->fill = nullptr; |
| } |
| |
| bool SVGResources::setStroke(LayoutSVGResourcePaintServer* stroke) |
| { |
| if (!stroke) |
| return false; |
| |
| if (!m_fillStrokeData) |
| m_fillStrokeData = FillStrokeData::create(); |
| |
| m_fillStrokeData->stroke = stroke; |
| return true; |
| } |
| |
| void SVGResources::resetStroke() |
| { |
| ASSERT(m_fillStrokeData); |
| ASSERT(m_fillStrokeData->stroke); |
| m_fillStrokeData->stroke = nullptr; |
| } |
| |
| bool SVGResources::setLinkedResource(LayoutSVGResourceContainer* linkedResource) |
| { |
| if (!linkedResource) |
| return false; |
| |
| m_linkedResource = linkedResource; |
| return true; |
| } |
| |
| void SVGResources::resetLinkedResource() |
| { |
| ASSERT(m_linkedResource); |
| m_linkedResource = nullptr; |
| } |
| |
| #ifndef NDEBUG |
| void SVGResources::dump(const LayoutObject* object) |
| { |
| ASSERT(object); |
| ASSERT(object->node()); |
| |
| fprintf(stderr, "-> this=%p, SVGResources(layoutObject=%p, node=%p)\n", this, object, object->node()); |
| fprintf(stderr, " | DOM Tree:\n"); |
| object->node()->showTreeForThis(); |
| |
| fprintf(stderr, "\n | List of resources:\n"); |
| if (m_clipperFilterMaskerData) { |
| if (LayoutSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper) |
| fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, clipper->element()); |
| if (LayoutSVGResourceFilter* filter = m_clipperFilterMaskerData->filter) |
| fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, filter->element()); |
| if (LayoutSVGResourceMasker* masker = m_clipperFilterMaskerData->masker) |
| fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, masker->element()); |
| } |
| |
| if (m_markerData) { |
| if (LayoutSVGResourceMarker* markerStart = m_markerData->markerStart) |
| fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->element()); |
| if (LayoutSVGResourceMarker* markerMid = m_markerData->markerMid) |
| fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", markerMid, markerMid->element()); |
| if (LayoutSVGResourceMarker* markerEnd = m_markerData->markerEnd) |
| fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", markerEnd, markerEnd->element()); |
| } |
| |
| if (m_fillStrokeData) { |
| if (LayoutSVGResourcePaintServer* fill = m_fillStrokeData->fill) |
| fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill, fill->element()); |
| if (LayoutSVGResourcePaintServer* stroke = m_fillStrokeData->stroke) |
| fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke, stroke->element()); |
| } |
| |
| if (m_linkedResource) |
| fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->element()); |
| } |
| #endif |
| |
| } // namespace blink |