1 | /* |
2 | * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
3 | * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org> |
4 | * Copyright (C) 2018 Apple Inc. All rights reserved. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this library; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | #include "SVGExternalResourcesRequired.h" |
24 | |
25 | #include "RenderSVGResource.h" |
26 | #include "RenderSVGShape.h" |
27 | #include "SVGElement.h" |
28 | #include "SVGNames.h" |
29 | |
30 | namespace WebCore { |
31 | |
32 | SVGExternalResourcesRequired::SVGExternalResourcesRequired(SVGElement* contextElement) |
33 | : m_contextElement(*contextElement) |
34 | , m_externalResourcesRequired(SVGAnimatedBoolean::create(contextElement)) |
35 | { |
36 | static std::once_flag onceFlag; |
37 | std::call_once(onceFlag, [] { |
38 | PropertyRegistry::registerProperty<SVGNames::externalResourcesRequiredAttr, &SVGExternalResourcesRequired::m_externalResourcesRequired>(); |
39 | }); |
40 | } |
41 | |
42 | void SVGExternalResourcesRequired::parseAttribute(const QualifiedName& name, const AtomicString& value) |
43 | { |
44 | if (name == SVGNames::externalResourcesRequiredAttr) |
45 | m_externalResourcesRequired->setBaseValInternal(value == "true" ); |
46 | } |
47 | |
48 | void SVGExternalResourcesRequired::svgAttributeChanged(const QualifiedName& attrName) |
49 | { |
50 | if (!isKnownAttribute(attrName)) |
51 | return; |
52 | if (!m_contextElement.isConnected()) |
53 | return; |
54 | |
55 | // Handle dynamic updates of the 'externalResourcesRequired' attribute. Only possible case: changing from 'true' to 'false' |
56 | // causes an immediate dispatch of the SVGLoad event. If the attribute value was 'false' before inserting the script element |
57 | // in the document, the SVGLoad event has already been dispatched. |
58 | if (!externalResourcesRequired() && !haveFiredLoadEvent() && !isParserInserted()) { |
59 | setHaveFiredLoadEvent(true); |
60 | |
61 | ASSERT(m_contextElement.haveLoadedRequiredResources()); |
62 | m_contextElement.sendSVGLoadEventIfPossible(); |
63 | } |
64 | |
65 | auto* renderer = m_contextElement.renderer(); |
66 | if (renderer && is<RenderSVGShape>(renderer)) { |
67 | SVGElement::InstanceInvalidationGuard guard(m_contextElement); |
68 | RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer); |
69 | } |
70 | } |
71 | |
72 | void SVGExternalResourcesRequired::addSupportedAttributes(HashSet<QualifiedName>& supportedAttributes) |
73 | { |
74 | supportedAttributes.add(SVGNames::externalResourcesRequiredAttr); |
75 | } |
76 | |
77 | void SVGExternalResourcesRequired::dispatchLoadEvent() |
78 | { |
79 | if (isParserInserted()) |
80 | ASSERT(externalResourcesRequired() != haveFiredLoadEvent()); |
81 | else if (haveFiredLoadEvent()) |
82 | return; |
83 | |
84 | // HTML and SVG differ completely in the 'onload' event handling of <script> elements. |
85 | // HTML fires the 'load' event after it sucessfully loaded a remote resource, otherwise an error event. |
86 | // SVG fires the SVGLoad event immediately after parsing the <script> element, if externalResourcesRequired |
87 | // is set to 'false', otherwise it dispatches the 'SVGLoad' event just after loading the remote resource. |
88 | if (!externalResourcesRequired()) |
89 | return; |
90 | |
91 | ASSERT(!haveFiredLoadEvent()); |
92 | |
93 | // Dispatch SVGLoad event |
94 | setHaveFiredLoadEvent(true); |
95 | ASSERT(m_contextElement.haveLoadedRequiredResources()); |
96 | |
97 | m_contextElement.sendSVGLoadEventIfPossible(); |
98 | } |
99 | |
100 | void SVGExternalResourcesRequired::insertedIntoDocument() |
101 | { |
102 | if (isParserInserted()) |
103 | return; |
104 | |
105 | // Eventually send SVGLoad event now for the dynamically inserted script element. |
106 | if (externalResourcesRequired()) |
107 | return; |
108 | setHaveFiredLoadEvent(true); |
109 | m_contextElement.sendSVGLoadEventIfPossibleAsynchronously(); |
110 | } |
111 | |
112 | void SVGExternalResourcesRequired::finishParsingChildren() |
113 | { |
114 | // A SVGLoad event has been fired by SVGElement::finishParsingChildren. |
115 | if (!externalResourcesRequired()) |
116 | setHaveFiredLoadEvent(true); |
117 | } |
118 | |
119 | bool SVGExternalResourcesRequired::haveLoadedRequiredResources() const |
120 | { |
121 | return !externalResourcesRequired() || haveFiredLoadEvent(); |
122 | } |
123 | |
124 | } |
125 | |