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